列表

详情


NC20499. [ZJOI2011]营救皮卡丘

描述

皮卡丘被火箭队用邪恶的计谋抢走了!这三个坏家伙还给小智留下了赤果果的挑衅!为了皮卡丘,也为了正义,小智和他的朋友们义不容辞的踏上了营救皮卡丘的道路。 火箭队一共有N个据点,据点之间存在M条双向道路。据点分别从1到N标号。
小智一行K人从真新镇出发,营救被困在N号据点的皮卡丘。为了方便起见,我们将真新镇视为0号据点,一开始K个人都在0号点。 由于火箭队的重重布防,要想摧毁K号据点,必须按照顺序先摧毁1到K-1号据点,并且,如果K-1号据点没有被摧毁,由于防御的连锁性,小智一行任何一个人进入据点K,都会被发现,并产生严重后果。因此,在K-1号据点被摧毁之前,任何人是不能够经过K号据点的。 
为了简化问题,我们忽略战斗环节,小智一行任何一个人经过K号据点即认为K号据点被摧毁。被摧毁的据点依然是可以被经过的。K个人是可以分头行动的,只要有任何一个人在K-1号据点被摧毁之后,经过K号据点,K号据点就被摧毁了。显然的,只要N号据点被摧毁,皮卡丘就得救了。 野外的道路是不安全的,因此小智一行希望在摧毁N号据点救出皮卡丘的同时,使得K个人所经过的道路的长度总和最少。 请你帮助小智设计一个最佳的营救方案吧!

输入描述

第一行包含三个正整数N,M,K。表示一共有N+1个据点,分别从0到N编号,以及M条无向边。
一开始小智一行共K个人均位于0号点。 
接下来M行,每行三个非负整数,第i行的整数为Ai,Bi,Li。表示存在一条从Ai号据点到Bi号据点的长度为Li的道路。

输出描述

仅包含一个整数S,为营救皮卡丘所需要经过的最小的道路总和。

示例1

输入:

3 4 2
0 1 1
1 2 1
2 3 100
0 3 1

输出:

3

说明:

【样例说明】
小智和小霞一起前去营救皮卡丘。在最优方案中,小智先从真新镇前往1号点,接着前往2号据点。当小智成功摧毁2号据点之后,小霞从真新镇出发直接前往3号据点,救出皮卡丘。

原站题解

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

C++ 解法, 执行用时: 47ms, 内存消耗: 1944K, 提交时间: 2021-11-13 13:20:32

#include<bits/stdc++.h>
using namespace std;
const int N=500;
const int M=1e6;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
int n,m,s,t,K,dist[N][N];
int head[N],ver[M],edgec[M],edgef[M],nxt[M],tot=1;
int flow[N],pre[N],d[N],vis[N];
void addedge(int x,int y,int f,int c){
	ver[++tot]=y,edgec[tot]=c,edgef[tot]=f;
	nxt[tot]=head[x];head[x]=tot;
	ver[++tot]=x,edgec[tot]=-c,edgef[tot]=0;
	nxt[tot]=head[y];head[y]=tot;
}
queue<int>que;
int spfa(){
	memset(pre,-1,sizeof(pre));
	memset(d,0x3f,sizeof(d));
	memset(vis,0,sizeof(vis));
	flow[s]=INF,vis[s]=1,d[s]=0;
	que.push(s);
	while(!que.empty()){
		int x=que.front();que.pop();
		vis[x]=0;
		for(int i=head[x];i!=-1;i=nxt[i]){
			int y=ver[i];
			if(d[y]>d[x]+edgec[i] && edgef[i]>0){
				d[y]=d[x]+edgec[i];
				pre[y]=i;
				flow[y]=min(flow[x],edgef[i]);
				if(!vis[y]){
					vis[y]=1;
					que.push(y);
				}
			}
		}
	}
	return d[t]!=INF;
}
int EK(){
	int ans=0;
	while(spfa()){
		int cur=t;
		while(cur!=s){
			int i=pre[cur];
			edgef[i]-=flow[t];
			edgef[i^1]+=flow[t];
			cur=ver[i^1];
		}
		ans+=flow[t]*d[t];
	}
	return ans;
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    cin>>n>>m>>K;
    memset(dist,0x3f,sizeof(dist));
    memset(head,-1,sizeof(head));
    for(int i=0;i<=n;i++)dist[i][i]=0;
    for(int i=1;i<=m;i++){
    	int a,b,l;cin>>a>>b>>l;
    	dist[a][b]=dist[b][a]=min(dist[a][b],l);
	}
	s=2*n+1,t=s+1;
	for(int k=0;k<=n;k++)
		for(int i=0;i<=n;i++)
			for(int j=0;j<=n;j++)
				if(k<=max(i,j))dist[i][j]=min(dist[i][j],dist[i][k]+dist[k][j]);
	addedge(s,0,K,0);
	for(int i=1;i<=n;i++){
		addedge(s,i,1,0);
		addedge(i+n,t,1,0);
	}
	for(int i=0;i<=n;i++)
		for(int j=i+1;j<=n;j++)
			addedge(i,j+n,1,dist[i][j]);
	cout<<EK();
    return 0;
}

上一题