1. 程式人生 > >[SCOI2008]城堡

[SCOI2008]城堡

rdquo scanf clu algo out fin mes tro 超過

題目描述

在一個國家裏,有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: 復制
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]城堡