洛谷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;
}

  

posted @ 2019-02-12 17:00  EM-LGH  阅读(143)  评论(0编辑  收藏  举报