NKOI 1946 航空路线

本文介绍了一种基于最大费用最大流算法解决特定航空路线问题的方法。该问题要求找到一条从最西端城市出发,途经尽可能多城市的旅行路线。文章详细阐述了如何将此问题转化为图论中的最大流问题,并通过具体示例展示了算法实现过程。

【线性规划与网络流24题 11】航空路线

Time Limit:10000MS  Memory Limit:65536K
Total Submit:18 Accepted:2 
Case Time Limit:1000MS

Description

给定一张航空图,图中顶点代表城市,边代表2城市间的直通航线。现要求找出一条满足下述限制条件的且途经城市最多的旅行路线。 
(1)从最西端城市出发,单向从西向东途经若干城市到达最东端城市,然后再单向从东向西飞回起点(可途经若干城市)。 
(2)除起点城市外,任何城市只能访问1次。 

编程任务: 
对于给定的航空图,试设计一个算法找出一条满足要求的最佳航空旅行路线。 

由于本OJ无Special Judge , 所以只需要输出最多经过的城市数

Input

第1 行有2个正整数N 和V,N 表示城市数,N<100,V 表示直飞航线数。 
接下来的N行中每一行是一个城市名,可乘飞机访问这些城市。 
城市名出现的顺序是从西向东。也就是说,设i,j 是城市表列中城市出现的顺序,当i>j 时,表示城市i 在城市j 的东边,而且不会有2 个城市在同一条经线上。城市名是一个长度不超过15 的字符串,串中的字符可以是字母或阿拉伯数字。例如,AGR34或BEL4。 
再接下来的V 行中,每行有2 个城市名,中间用空格隔开,如 city1 city2 表示city1到city2 有一条直通航线,从city2 到city1 也有一条直通航线。

Output

一行,包含一个整数或字符串,表示最多经过的城市数,如果无解,则输出"No Solution!"(不包含引号)

Sample Input

8 9
Vancouver
Yellowknife
Edmonton
Calgary
Winnipeg
Toronto
Montreal
Halifax
Vancouver Edmonton
Vancouver Calgary
Calgary Winnipeg
Winnipeg Toronto
Toronto Halifax
Montreal Halifax
Edmonton Montreal
Edmonton Yellowknife
Edmonton Calgary

Sample Output

7

Source

感谢 Wo_ai_WangYuan 修改题目并放上数据


这题要用到最大费用最大流

把问题抽象成图论问题,数学模型是求从S到T的两条不相交的路径,使得路径上点的权值之和最大。
费用流建模,首先拆点,把顶点x拆成x和x',x 与x'之间连接一条费用为1,容量为1的有向边;  

特殊地,1和n两个节点拆分后点内边容量设为2

对于与x相连的点a(a>x)x'向a连一条费用为0,容量为1的边。

最后再特判一下无解的情况

#include<cstdio>
#include<iostream>
#include<cstring>
#include<map> 
#include<vector>
#include<queue>
using namespace std;
const int maxn=505,inf=1e9;
string ss,tt;
int n,m,last[maxn],path[maxn],op,ed;
int dis[maxn],vd[maxn],maxflow,mincost;
bool flag[maxn];
map<string,int>id;
struct wr{   
    int a,b,c,w,NEXT;
    wr(int a,int b,int w,int c,int NEXT):a(a),b(b),w(w),c(c),NEXT(NEXT){}   
};   
vector<wr>s;   
void insert(int a,int b,int w,int c){  
    s.push_back(wr(a,b,w,c,last[a]));   
    last[a]=s.size()-1;   
    s.push_back(wr(b,a,-w,0,last[b]));   
    last[b]=s.size()-1;   
}   
struct wk{         
    int  n;              
    void init(int n){   
        this->n =n;   
        memset(last,-1,sizeof(last));   
    }                            
    bool find(int st,int nd){         
        int i;  
        queue<int>q;         
        for(i=1;i<=n;i++)dis[i]=-inf,path[i]=-1;   
        dis[st]=0,path[st]=0,flag[st]=1;     
        q.push(st);         
        while(!q.empty()){         
            int x=q.front();         
            q.pop();flag[x]=0;    
             for(i=last[x];i!=-1;i=s[i].NEXT){     
                 wr& e=s[i];           
                if(e.c>0&&dis[x]+e.w>dis[e.b]){         
                    dis[e.b]=dis[x]+e.w;   
                    path[e.b]=i;         
                    if(!flag[e.b]){         
                        q.push(e.b) ;         
                        flag[e.b]=1;         
                    }         
                }          
            }         
        }     
        return dis[nd]>-inf;           
    }         
}spfa;     
void addflow(){   
    int flow=inf,i;   
    for(i=ed;i!=op&&s[path[i]].a!=0;i=s[path[i]].a)   
        flow=min(flow,s[path[i]].c);   
    maxflow+=flow;   
    mincost+=dis[ed]*flow;   
    for(i=ed;i!=op;i=s[path[i]].a){   
        int x=path[i];   
        s[x].c-=flow;   
        s[x^1].c+=flow;   
    }   
}        
int main(){
	cin>>n>>m;
	int i,j;
	op=1,ed=2*n;
	spfa.init(ed);
	for(i=1;i<=n;i++){
		cin>>ss;
		id[ss]=i;
		if(i==1||i==n)insert(i,i+n,1,2);
		else insert(i,i+n,1,1);
	}
	for(i=1;i<=m;i++){
		cin>>ss>>tt;
		int id1=id[ss],id2=id[tt];
		if(id1>id2)swap(id1,id2);
		insert(id1+n,id2,0,1);
	}
	while(spfa.find(op,ed))addflow();   
    if(maxflow==1&&mincost==2) printf("2");
    else if(maxflow!=2)printf("No Solution!");
    else printf("%d",mincost-2);
} 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值