zoukankan      html  css  js  c++  java
  • POJ 2157 Evacuation Plan [最小费用最大流][消圈算法]

    ---恢复内容开始---

    题意略。

    这题在poj直接求最小费用会超时,但是题意也没说要求最优解。

    根据线圈定理,如果一个跑完最费用流的残余网络中存在负权环,那么顺着这个负权环跑流量为1那么会得到更小的费用。

    关键是坑在找环的起点。其实看了代码之后发现的确不难...

    #include<stdio.h>
    #include<queue>
    #include<string.h>
    #define MAXN 300
    #define MAXM 30002*4
    #define INF  10000000
    using namespace std;
    //起点编号必须最小,终点编号必须最大
    bool vis[MAXN];                    //spfa中记录是否在队列里边
    int sum[105],nnum[MAXN],zhong;
    struct point{
        int x,y,c;
    }from[105],to[105];
    struct edge{
        edge *next,*op;                //op是指向反向边
        int t,c,v;                     //t下一个点编号,c容量,v权值
    }ES[MAXM],*V[MAXN];                //ES边静态邻接表,V点的编号
    int N,M,S,T,EC=-1;                 //S源点最小,T汇点最大,EC当前边数
    int demond[MAXN],sp[MAXN],prev[MAXN]; //spSPFA中记录距离,prev记录上一个点路径
    edge *path[MAXN];                  //与prev同步记录,记录到上一条边
    int cal(point a,point b){
        return max(a.x-b.x,b.x-a.x)+max(a.y-b.y,b.y-a.y)+1;
    }
    void addedge(int a,int b,int v,int c,int cc){
        edge e1={V[a],0,b,c,v},e2={V[b],0,a,cc,-v};
        ES[++EC]=e1;V[a]=&ES[EC];
        ES[++EC]=e2;V[b]=&ES[EC];
        V[a]->op=V[b];V[b]->op=V[a];
    }
    bool SPFA(int st,int up){
        int u,v;
        memset(nnum,0,sizeof(nnum));
        memset(vis,0,sizeof(vis));
        for(u=1;u<=up;u++){
            sp[u]=INF;
        }
        queue<int>q;
        q.push(st);
        sp[st]=0;
        vis[st]=1;
        nnum[st]++;
        while(!q.empty()){
            u=q.front();
            vis[u]=0;
            q.pop();
            for(edge *k=V[u];k;k=k->next){
                v=k->t;
                if(k->c>0&&sp[u]+k->v<sp[v]){
                    sp[v]=sp[u]+k->v;
                    prev[v]=u;
                    path[v]=k;
                    if(vis[v]==0){
                        nnum[v]++;
                        if(nnum[v]>=up){
                            zhong=v;
                            return 1;
                        }
                        vis[v]=1;
                        q.push(v);
                    }
                }
            }
        }
        return 0;
    }
    int argument(){
        memset(vis,0,sizeof(vis));
        int i,cost=1,flow=0;
        edge *e;
        for(i=zhong;;i=prev[i]){
            if(vis[i]==0)vis[i]=1;
            else break;
        }
        zhong=i;
        bool ok=0;
        memset(vis,0,sizeof(vis));
        for(i=zhong;;){
            if(!vis[i])vis[i]=1;
            else break;
            e=path[i];
            e->c-=cost;e->op->c+=cost;
            flow+=e->v*cost;
            vis[i]=1;
            i=prev[i];
            //if(i==zhong)break;
        }
        return flow;
    }
    int maxcostflow(int tans,int up){
        int Flow=tans;
        if(SPFA(1,up)){
            Flow+=argument();
        }
        return Flow;
    }
    void init(){
        int n,m;
        while(scanf("%d%d",&n,&m)!=EOF){
            EC=-1;
            memset(sum,0,sizeof(sum));
            int tans=0;
            for(int i=0;i<MAXN;i++){
                V[i]=NULL;
            }
            for(int i=0;i<n;i++){
                scanf("%d%d%d",&from[i].x,&from[i].y,&from[i].c);
            }
            for(int i=0;i<m;i++){
                scanf("%d%d%d",&to[i].x,&to[i].y,&to[i].c);
            }
            for(int i=0;i<n;i++){
                for(int j=0;j<m;j++){
                    int tmp;
                    scanf("%d",&tmp);
                    addedge(i+1,j+1+n,cal(from[i],to[j]),INF,tmp);
                    tans+=cal(from[i],to[j])*tmp;
                    sum[j]+=tmp;
                }
            }
            T=n+m+1;
            for(int i=1;i<=m;i++){
                addedge(i+n,T,0,to[i-1].c-sum[i-1],sum[i-1]);
            }
            int ans=maxcostflow(tans,T);
            if(ans==tans)puts("OPTIMAL");
            else{
                puts("SUBOPTIMAL");
                for(int i=0;i<n;i++){
                    for(int j=0;j<m;j++){
                        for(edge *k=V[j+1+n];k;k=k->next){
                            if(k->t==i+1){
                                printf("%d",k->c);
                                if(j!=m-1)printf(" ");
                                else printf("
    ");
                                break;
                            }
                        }
                    }
                }
            }
        }
    }
    int main(){
        init();
        return 0;
    }

    ---恢复内容结束---

  • 相关阅读:
    Android漂亮的对话框项目sweet-alert-dialog
    JAVA并发编程4_线程同步之volatile关键字
    JAVA并发编程3_线程同步之synchronized关键字
    JAVA并发编程2_线程安全&内存模型
    JAVA并发编程1_多线程的实现方式
    JAVA 反射
    第五百三十九天 how can I 坚持
    第五百三十八天 how can I 坚持
    第五百三十七天 how can I 坚持
    第五百三十六天 how can I 坚持
  • 原文地址:https://www.cnblogs.com/tun117/p/5418230.html
Copyright © 2011-2022 走看看