[SCOI2008]城堡
阿新 • • 發佈:2017-10-28
rdquo scanf clu algo out fin mes tro 超過
輸入樣例#3: 復制
題目描述
在一個國家裏,有n個城市(編號為0 到n-1)。這些城市之間有n條雙向道
路相連(編號為0 到n-1),其中編號為i的道路連接了城市i和城市ri(一條道
路可以連接一個城市和它自身),長度為di。n 個城市中有m個擁有自己城堡,
可以抵禦敵人侵略。如果沒有城堡的城市遭受攻擊,則離它最近的城堡將派兵前
往救援。
你的任務是在不超過k個沒有城堡的城市中建立城堡,使得所有城市中“離
最近城堡的距離”的最大值盡量小。換句話說,若令dist(c)表示城市c的最近城
堡離它的距離,則你的任務是讓max{dist(c)}盡量小。
輸入數據保證存在方案使得對於每個城市,至少有一個城堡能夠到達。
輸入輸出格式
輸入格式:
輸入第一行為三個正整數n, m, k。第二行包含n個整數r0,r1,…,rn-1。第三行
包含n 個整數d0,d1,…,dn-1。第四行包含m 個各不相同的0~n-1 之間的整數,分
別為m個城堡所在的城市編號。
輸出格式:
輸出僅一行,包含一個整數,即max{dist(c)}的最小值。
輸入輸出樣例
輸入樣例#1: 復制5 0 1 1 2 3 4 0 1 1 1 1 1輸出樣例#1: 復制
2輸入樣例#2: 復制
3 1 1 1 2 0 1 2 3 2輸出樣例#2: 復制
1
3 1 1 1 2 0 1 2 3 2輸出樣例#3: 復制
0輸入樣例#4: 復制
10 3 3 0 2 0 0 2 2 8 3 8 7 10 9 1 8 1 3 7 2 8 1 3 4 6輸出樣例#4: 復制
3輸入樣例#5: 復制
2 0 1 1 0 5 10輸出樣例#5: 復制
5
說明
100%的數據滿足:2<=n<=50, 1<=di<=106, 0<=m<=n-k
先存圖,直接用floyd求出最短路
繼續二分最大長度mid,對於每個已有城堡的城市,直接去標記其能到達的城市
然後對於不能到達的
我們將其距離不超過枚舉的mid的點期望+1,分別在k次中每次找到最大期望的值進行建城堡。
有個玄學:在比較找出最大期望相同時要找編號盡量大的?????
復雜度O(n^3+logd*k*n^2)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 int n,m,k; 7 long long dis[101][101]; 8 int cnt[101],vis[101],ans,p[101],son[101]; 9 void find(int mid) 10 {int i,j,Max,maxi; 11 memset(cnt,0,sizeof(cnt)); 12 for (i=1;i<=n;i++) 13 if (vis[i]==0) 14 { 15 for (j=1;j<=n;j++) 16 if (dis[i][j]<=mid) 17 cnt[j]++; 18 } 19 Max=0,maxi=0; 20 for (i=1;i<=n;i++) 21 if (cnt[i]>=Max) 22 { 23 Max=cnt[i]; 24 maxi=i; 25 } 26 if (maxi==0) return; 27 for (i=1;i<=n;i++) 28 if (dis[maxi][i]<=mid) vis[i]=1; 29 } 30 bool check(int mid) 31 {int i,j; 32 memset(vis,0,sizeof(vis)); 33 for (i=1;i<=m;i++) 34 { 35 for (j=1;j<=n;j++) 36 if (dis[p[i]][j]<=mid) vis[j]=1; 37 } 38 for (i=1;i<=k;i++) 39 find(mid); 40 for (i=1;i<=n;i++) 41 if (vis[i]==0) return 0; 42 return 1; 43 } 44 int main() 45 {int i,j; 46 long long d; 47 cin>>n>>m>>k; 48 memset(dis,127/2,sizeof(dis)); 49 for (i=1;i<=n;i++) 50 { 51 scanf("%d",&son[i]); 52 son[i]++; 53 } 54 int l=0,r=0; 55 for (i=1;i<=n;i++) 56 { 57 scanf("%lld",&d); 58 dis[i][son[i]]=min(dis[i][son[i]],d); 59 dis[son[i]][i]=min(dis[i][son[i]],d); 60 r+=d; 61 } 62 for (l=1;l<=n;l++) 63 for (i=1;i<=n;i++) 64 if (i!=l) 65 { 66 for (j=1;j<=n;j++) 67 if (l!=j&&i!=j) 68 { 69 dis[i][j]=min(dis[i][j],dis[i][l]+dis[l][j]); 70 } 71 } 72 for (i=1;i<=n;i++) 73 dis[i][i]=0; 74 for (i=1;i<=m;i++) 75 scanf("%d",&p[i]),p[i]++; 76 l=0; 77 while (l<=r) 78 { 79 int mid=(l+r)/2; 80 if (check(mid)) ans=mid,r=mid-1; 81 else l=mid+1; 82 } 83 cout<<ans; 84 }
[SCOI2008]城堡