zoukankan      html  css  js  c++  java
  • 洛谷P2770 航空路线问题 最小费用流

    水题.   

    本质上题目要求的是一个包含 $1$,$n$ 的最大环,所以每个点只可以经过一次.     

    那么就拆点,然后限制每个点的经过次数就行了.    

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<vector>
    #include<cstring>
    #include<queue>
    #include<string>
    #include<map>
    using namespace std;
    const int maxn=800;
    const int INF=1000000+23666;
    typedef long long ll;
    map<string,int>idx;
    string A[maxn];
    int viss[maxn];
    int s,t,n;
    struct Edge{
    	int from,to,cap,cost;
    	Edge(int u,int v,int c,int f):from(u),to(v),cap(c),cost(f){}
    };
    vector<Edge>edges;
    vector<int>G[maxn];
    struct MCMF{
        int d[maxn],inq[maxn],a[maxn],flow2[maxn];
        queue<int>Q;
        ll ans=0;
        int flow=0;
        void addedge(int u,int v,int c,int f){
        	edges.push_back(Edge(u,v,c,f));    //正向弧
        	edges.push_back(Edge(v,u,0,-f));   //反向弧
        	int m=edges.size();
        	G[u].push_back(m-2);
        	G[v].push_back(m-1);
        }
        int SPFA(){
        	for(int i=0;i<=n;++i)d[i]=INF,flow2[i]=INF;
        	memset(inq,0,sizeof(inq));int f=INF;
        	d[s]=0,inq[s]=1;Q.push(s);
            while(!Q.empty()){
            	int u=Q.front();Q.pop();inq[u]=0;
            	int sz=G[u].size();
            	for(int i=0;i<sz;++i){
                      Edge e=edges[G[u][i]];
                      if(e.cap>0&&d[e.to]>d[u]+e.cost){
                          a[e.to]=G[u][i];
                          d[e.to]=d[u]+e.cost;
                          flow2[e.to]=min(flow2[u],e.cap);
                          if(!inq[e.to]){inq[e.to]=1;Q.push(e.to);}
                      }
            	}
            }
            if(d[t]==INF)return 0;
            f=flow2[t];
            flow+=f;
            int u=edges[a[t]].from;
            edges[a[t]].cap-=f;
            edges[a[t]^1].cap+=f;
            while(u!=s){
            	edges[a[u]].cap-=f;
            	edges[a[u]^1].cap+=f;
            	u=edges[a[u]].from;
            }
            ans+=(ll)(d[t]*f);
            return 1;
        }
        int maxflow(){
            while(SPFA());
            return flow;
        }
        ll getcost(){return ans;}
    }op;
    void print(int x){
    	if(x==t-1)return;
    	int sz=G[x+1].size();
    	for(int i=0;i<sz;++i){
    		int e=G[x+1][i];
    		if(e%2==0&&edges[e].cap==0&&!viss[e]){
    			print(edges[e].to);
    			cout<<A[x]<<endl;
    			return;
    		}
    	}
    }
    int main(){
    	int N,M;cin>>N>>M;
    	int cnt=1;
    	for(int i=1;i<=N;++i){
    		string s;cin>>s;idx[s]=cnt;A[cnt]=s;
    		if(i==1||i==N)op.addedge(cnt,cnt+1,2,0);
    		else op.addedge(cnt,cnt+1,1,0);
    		cnt+=2;
    	}
    	n=cnt-1,s=1,t=n;
    	for(int i=1;i<=M;++i)
    	{
              string a,b;cin>>a>>b; 
              int ax=idx[a],bx=idx[b];
              if(ax<bx)op.addedge(ax+1,bx,1,-1);
              else op.addedge(bx+1,ax,1,-1);
    	}
         int F=op.maxflow();
         ll ans=op.getcost();
         if(F!=2)
         {
             if(ans==-1){
             	   cout<<2<<endl;
             	   cout<<A[s]<<endl;
             	   cout<<A[t-1]<<endl;
             	   cout<<A[s]<<endl;
             	   return 0;
             }
             else {cout<<"No Solution!"<<endl;return 0;}
         }
         cout<<-ans<<endl;
         int tr=s;
         cout<<A[s]<<endl;
         do
         {
            ++tr;
            int sz=G[tr].size();
            for(int i=0;i<sz;++i){
            	int e=G[tr][i];
            	if(e%2==0&&edges[e].cap==0){tr=edges[e].to,viss[e]=1;break;}
            }
            if(tr!=t)cout<<A[tr]<<endl;
         }while(tr!=t);
         print(s);
         return 0;
    }
    

      

  • 相关阅读:
    Linux 下杀毒可用工具 clamav
    Docker 添加环境系统文件配置
    Docker 空间大小设置
    Docker 扩容 容器空间大小
    bzoj 1088 DP
    bzoj 1096 斜率优化DP
    spoj p104 Matrix-Tree定理
    bzoj 1016 深搜
    WC后记
    bzoj 1301 后缀数组
  • 原文地址:https://www.cnblogs.com/guangheli/p/10365910.html
Copyright © 2011-2022 走看看