• [SCOI2008]城堡


    题目描述

    在一个国家里,有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 }
  • 相关阅读:
    ABAP Help Document(2):1.2 表达式
    ABAP Help Document(1):1.1关键字
    api——》将.doc文件转成.docx文件后缀,且仅需要输入单个文件绝对路径
    python 更改默认输出 解决编码常出错问题
    爬取法律法规代码(可直接使用)
    python datetime 模块详解
    python 获得日期列表中最大日期(能够剔出不是日期类型)
    博客园页面css
    日期大小比较令解决{strftime('%Y年%m月%d日')}出错问题
    CodeForces
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/7746194.html
Copyright © 2020-2023  润新知