列表

详情


NC20261. [SCOI2008]城堡CASTLE

描述

在一个国家里,有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

输出:

2

示例2

输入:

3 1 1
1 2 0
1 2 3
2

输出:

1

示例3

输入:

2 1 1  
0 1  
1 1  
1 

输出:

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

输出:

3

示例5

输入:

2 0 1
1 0
5 10

输出:

5

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 4ms, 内存消耗: 396K, 提交时间: 2022-10-24 17:27:23

#include<cstdio>
#include<cstring>
#define Min(a,b) ((a)>(b)?(b):(a))
using namespace std;
const int INF=0x7ffffff;
int n,m,k,x,i,j,l;
int L,R,mid;
int r[55],d[55],h[55];
int dt[55][55];
bool judge(int x)
{
    int temp=k,tot=m,i,j,t,u,v;
    int c[55],p[55];
    for (i=0;i<n;i++)c[i]=h[i];
    for (i=0;i<n;i++)
    if (!c[i])
    {
        t=INF;
        for (j=0;j<n;j++)
        if (c[j]==1)t=Min(t,dt[i][j]);
        if (t<=x)c[i]=2,tot++;
    }
    if (tot==n)return 1;
    while (temp--)
    {
        memset(p,0,sizeof(p));
        for (i=0;i<n;i++)
        if (!c[i])
        {
            for (j=0;j<n;j++)
            if (c[j]!=1&&dt[i][j]<=x)p[j]++;
        }
        u=0;
        for (i=0;i<n;i++)
        if (c[i]!=1&&p[i]>=u)u=p[i],v=i;
        if (!c[v])tot++;c[v]=1;
        for (i=0;i<n;i++)
        if (!c[i])
        {
            t=INF;
            for (j=0;j<n;j++)
            if (c[j]==1)t=Min(t,dt[i][j]);
            if (t<=x)c[i]=2,tot++;
        }
        if (tot==n)return 1;
    }
    return 0;
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for (i=0;i<n;i++)
    for (j=0;j<n;j++)
    dt[i][j]=(i==j)?0:INF;
    for (i=0;i<n;i++)scanf("%d",&r[i]);
    for (i=0;i<n;i++)
    {
        scanf("%d",&d[i]);R+=d[i];
        dt[i][r[i]]=dt[r[i]][i]=Min(dt[i][r[i]],d[i]);
    }
    for (i=1;i<=m;i++)
    {
        scanf("%d",&x);
        h[x]=1;
    }
    for (l=0;l<n;l++)
    for (i=0;i<n;i++)
    for (j=0;j<n;j++)
    if (i!=j&&i!=l&&j!=l)
    if (dt[i][l]+dt[l][j]<dt[i][j])
    dt[i][j]=dt[i][l]+dt[l][j];
    L=0;
    while (L<=R)
    {
        mid=(L+R)>>1;
        if (judge(mid))R=mid-1;
        else L=mid+1;
    }
    printf("%d\n",L);
}

C++11(clang++ 3.9) 解法, 执行用时: 28ms, 内存消耗: 376K, 提交时间: 2019-12-15 08:28:35

#include<bits/stdc++.h>
#define N 61
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
int n,m,k,g[N],h[N],b[N],cnt,dis[N][N],a[N],d;
bool f[N];
int solve()
{
	memcpy(h,g,sizeof(g));
	fo(i,1,k)fo(j,1,n)h[j]=min(h[j],dis[b[i]][j]);
	int ans=0;
	fo(i,1,n)ans=max(ans,h[i]);
	return ans;
}
int main()
{
	srand(time(0));
	scanf("%d%d%d",&n,&m,&k);
	fo(i,1,n)scanf("%d",&a[i]),a[i]++;
	memset(g,0x7f,sizeof(g));
	memset(dis,0x3f,sizeof(dis));
	fo(i,1,n)dis[i][i]=0,scanf("%d",&d),dis[i][a[i]]=dis[a[i]][i]=min(dis[i][a[i]],d);
	fo(l,1,n)fo(i,1,n)fo(j,1,n)dis[i][j]=min(dis[i][j],dis[i][l]+dis[l][j]);
	fo(i,1,m)scanf("%d",&d),f[++d]=1;
	fo(i,1,n)
		if(!f[i])b[++cnt]=i;
	else
		fo(j,1,n)g[j]=min(g[j],dis[i][j]); 
	random_shuffle(b+1,b+cnt+1);
	int T=5,pre,ans=solve();
	while(T--)
	{
		random_shuffle(b+1,b+cnt+1);
		ans=min(ans,solve());
		int G=20;
		while (G--)
		{
			fo(i,k+1,cnt)
				fo(j,1,k)
				{
					swap(b[i],b[j]);
					pre=ans,ans=solve();
					if(ans>pre)ans=pre,swap(b[i],b[j]);
				}
		}
	}
	printf("%d",ans);
}

上一题