CDOJ UESTC 1220 The Battle of Guandu

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=10000000000;
const int maxn=300000+10;
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=0; i<maxn; i++) G[i].clear();
    if(!Q.empty()) Q.pop();
    for(int i=0; i<maxn; i++) dis[i]=INF;
    memset(flag,0,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=0;
    init();
    scanf("%d%d",&N,&M);
    for(int i=1; i<=N; i++) scanf("%d",&x[i]);
    for(int i=1; i<=N; i++) scanf("%d",&y[i]);
    for(int i=1; i<=N; i++) scanf("%lld",&c[i]);
    for(int i=1; i<=M; i++) scanf("%d",&w[i]);

    for(int i=1; i<=N; i++) add(y[i],x[i],c[i]);
    for(int i=1; i<=M; i++)
    {
        if(w[i]==0) add(0,i,0);
        else if(w[i]==2) add(i,M+1,0);
    }
}

void spfa()
{
    flag[0]=1;
    Q.push(0);
    dis[0]=0;
    while(!Q.empty())
    {
        int h=Q.front();
        Q.pop();
        flag[h]=0;
        for(int i=0; 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]=1;
                    Q.push(e[id].to);
                }
            }
        }
    }
}

int main()
{
    scanf("%d",&T);
    for(int Case=1; Case<=T; Case++)
    {
        read();
        spfa();
        long long ans=0;
        for(int i=1; i<=M; i++)
        {
            if(w[i]==2)
            {
                if(dis[i]==INF)
                {
                    ans=-1;
                    break;
                }
                ans=ans+dis[i];
            }
        }
        printf("Case #%d: %lld\n",Case,ans);
    }
    return 0;
}

 

posted @ 2015-10-27 09:02  Fighting_Heart  阅读(174)  评论(0编辑  收藏  举报