1. 程式人生 > 實用技巧 >【UOJ 668】一個圖的問題

【UOJ 668】一個圖的問題

【題目描述】:

有一個n個點n條邊的有向圖(每個點一條出邊,可能有自環,節點編號0~N-1),每條邊為,意思是i指向f(i)的邊權為w(i)的邊,現在小A想知道,對於每個點的si和mi。

si:由i出發經過k條邊,這k條邊的權值和。

mi:由i出發經過k條邊,這k條邊的權值最小值。

【輸入描述】:

第一行兩個數n和k

第二行n個數f(i)

第三行n個數w(i)

【輸出描述】:

每行兩個數si和mi

【樣例輸入】:

7 3
1 2 3 4 3 2 6
6 3 1 4 2 2 3

【樣例輸出】:

10 1
8 1
7 1
10 2
8 2
7 1
9 3

【時間限制、資料範圍及描述】:

時間:1s 空間:512M

30%的資料:n,k<=1000。

100%的資料:N<=10^5,k<=10^10,0<=f(i)<n,w(i)<=10^8。

題解:30分的暴力dfs如下(考場沒想到是倍增阿巴阿巴阿巴~等我寫好倍增就傳程式碼子~

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<bits/stdc++.h>
typedef long
long ll; using namespace std; const int N=100002; int n,k,ans1,ans2; int to[N],w[N]; void dfs(int mn,int now,int pace,int sum){ if(pace==k) { ans1=sum; ans2=mn; return ; } dfs(min(w[now],mn),to[now],pace+1,sum+w[now]); } int main(){ freopen("graph.in","r",stdin); freopen("graph.out","w"
,stdout); scanf("%d %d",&n,&k); for(int i=0;i<n;i++) { scanf("%d",&to[i]); } for(int i=0;i<n;i++) { scanf("%d",& w[i]); } for(int i=0;i<n;i++) { dfs(0x3f3f3f3f,i,0,0); printf("%d %d\n",ans1,ans2); } return 0; }