[計蒜客16959] Colored Graph [2017 ACM-ICPC 亞洲區(烏魯木齊賽區)網絡賽 J]

題意

從大連到上海再到西安,不能通過同一個點兩次,求最短路徑

題解

建費用流,流的費用爲長度,對城市拆點限制流量即可滿足不通過同一個點兩次。

代碼

#include <bits/stdc++.h>

#define  infi 0x3f3f3f3fLL
#define  kN   40010LL
#define  kM   120010LL

using namespace std;
struct FST {int to,next,flow,cost;}e[kM<<1];
int star[kN], te;
void FST_init() {memset(star,0,sizeof star);te=1;}
void AddEdge(int u,int v,int cap,int cost) {
    te++;
    e[te].to=v;e[te].next=star[u];star[u]=te;
    e[te].flow=cap,e[te].cost=cost;
    te++;
    e[te].to=u;e[te].next=star[v];star[v]=te;
    e[te].flow=0,e[te].cost=-cost;
}

deque<int>q;
bool inq[kN];
int dis[kN],pre[kN];
int S,T,MCMF,FLOW;
bool spfa() {
    int u,v,p,aug;
    memset(dis,0x3f,sizeof dis);
    q.push_back(S);
    dis[S]=0,pre[S]=0;
    while(!q.empty())
        for(u=q.front(),q.pop_front(),inq[u]=false,p=star[u];p;p=e[p].next)
            if(v=e[p].to,e[p].flow>0&&dis[v]>dis[u]+e[p].cost)
                if(dis[v]=dis[u]+e[p].cost,pre[v]=p,!inq[v])
                    if(inq[v]=true,!q.empty()&&dis[v]<dis[q.front()]) q.push_front(v);
                    else q.push_back(v);
    if (dis[T]==infi) return false;
    aug = infi;
    for(p=pre[T];p;p=pre[e[p^1].to])
        if (aug>e[p].flow) aug=e[p].flow;
    for(p=pre[T];p;p=pre[e[p^1].to])
        e[p].flow-=aug,e[p^1].flow+=aug;
    MCMF += dis[T]*aug;
    FLOW += aug;
    return true;
}

char str[1000];
string ReadCity() {
    //scanf("%s",str);
    //string ret = str;
    string ret;
    cin>>ret;
    return ret;
}

map<string,int>ID;
int idx=0;

int reg(string a) {
    if (ID.find(a)!=ID.end()) return ID[a];
    idx++;
    ID[a] = idx;
    return idx;
}

inline void work() {
    int i,j,k,l,m;
    ID.clear();
    FST_init();
    idx=0;
    string DL = "Dalian";
    string SH = "Shanghai";
    string XA = "Xian";
    reg(DL),reg(SH),reg(XA);
    string a,b;
    //scanf("%d",&m);
    cin>>m;
    for(i=1;i<=m;i++) {
        a=ReadCity(),b=ReadCity();//,scanf("%d",&l);
        cin>>l;
        j=reg(a),k=reg(b);
        AddEdge(j*2,k*2-1,1,l);
        AddEdge(k*2,j*2-1,1,l);
    }
    j = reg(SH);
    S = j*2-1;
    T = idx*2+1;
    for(i=1;i<=idx;i++) {
        if (i == j) AddEdge(i*2-1,i*2,2,0);
        else AddEdge(i*2-1,i*2,1,0);
    }
    j = reg(DL);
    AddEdge(j*2,T,1,0);
    j = reg(XA);
    AddEdge(j*2,T,1,0);
    MCMF=FLOW=0;
    while(spfa());
    if (FLOW==2) printf("%d\n",MCMF);
    else puts("-1");
}

int main() {
    int T;
    //scanf("%d",&T);
    cin>>T;
    while(T-->0) work();
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章