The 2015 China Collegiate Programming Contest
2015第一届中国大学生程序设计竞赛 F题
本质就是求单源最短路!注意会爆int
对于每一个村庄i,其实就是花费c[i],把一个人从y[i]转移到x[i];
如果一张图中,不存在w[i]==2的节点,那么花费肯定是0。
所以,花费就出在w[i]==2的节点上,怎么处理这些节点呢?
可以从w[i]==0的节点上流出一些人,流到w[i]==2的节点上,并且对于每个w[i]==2的节点只需要一个人。
因此,设立一个节点S,连向所有w[i]==0的节点,费用为0;
对于每一个村庄i,从y[i]到x[i]连边,费用为c[i];
然后从S出发,跑单源最短路,最终把S到w[i]==2的节点的最短路都加起来就是答案。
如果有一个w[i]==2的节点不能到达,那么就输出-1.
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std; const long long INF=;
const int maxn=+;
int T,N,M;
int x[maxn],y[maxn];
long long c[maxn];
int w[maxn]; vector<int>G[maxn];
queue<int>Q;
bool flag[maxn];
long long dis[maxn]; struct Edge
{
int from,to;
long long cost;
} e[maxn];
int tot; void init()
{
for(int i=; i<maxn; i++) G[i].clear();
if(!Q.empty()) Q.pop();
for(int i=; i<maxn; i++) dis[i]=INF;
memset(flag,,sizeof flag);
} void add(int x,int y,long long c)
{
tot++;
e[tot].from=x;
e[tot].to=y;
e[tot].cost=c;
G[x].push_back(tot);
} void read()
{
tot=;
init();
scanf("%d%d",&N,&M);
for(int i=; i<=N; i++) scanf("%d",&x[i]);
for(int i=; i<=N; i++) scanf("%d",&y[i]);
for(int i=; i<=N; i++) scanf("%lld",&c[i]);
for(int i=; i<=M; i++) scanf("%d",&w[i]); for(int i=; i<=N; i++) add(y[i],x[i],c[i]);
for(int i=; i<=M; i++)
{
if(w[i]==) add(,i,);
else if(w[i]==) add(i,M+,);
}
} void spfa()
{
flag[]=;
Q.push();
dis[]=;
while(!Q.empty())
{
int h=Q.front();
Q.pop();
flag[h]=;
for(int i=; i<G[h].size(); i++)
{
int id=G[h][i];
if(dis[h]+e[id].cost<dis[e[id].to])
{
dis[e[id].to]=dis[h]+e[id].cost;
if(!flag[e[id].to])
{
flag[e[id].to]=;
Q.push(e[id].to);
}
}
}
}
} int main()
{
scanf("%d",&T);
for(int Case=; Case<=T; Case++)
{
read();
spfa();
long long ans=;
for(int i=; i<=M; i++)
{
if(w[i]==)
{
if(dis[i]==INF)
{
ans=-;
break;
}
ans=ans+dis[i];
}
}
printf("Case #%d: %lld\n",Case,ans);
}
return ;
}