P2770 航空路线问题

\(\color{#0066ff}{题目描述}\)

给定一张航空图,图中顶点代表城市,边代表 2 城市间的直通航线。现要求找出一条满足下述限制条件的且途经城市最多的旅行路线。

(1)从最西端城市出发,单向从西向东途经若干城市到达最东端城市,然后再单向从东向西飞回起点(可途经若干城市)。

(2)除起点城市外,任何城市只能访问 1 次。

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

\(\color{#0066ff}{输入格式}\)

第 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 也有一条直通航线。

\(\color{#0066ff}{输出格式}\)

文件第 1 行是旅行路线中所访问的城市总数 M。 接下来的 M+1 行是旅行路线的城市名,每行写 1 个城市名。首先是出发城市名,然后按访问顺序列出其它城市名。 注意,最后 1 行(终点城市)的城市名必然是出发城市名。如果问题无解,则输出“No Solution!”。

\(\color{#0066ff}{输入样例}\)

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

\(\color{#0066ff}{输出样例}\)

7
Vancouver
Edmonton
Montreal
Halifax
Toronto
Winnipeg
Calgary
Vancouver 

\(\color{#0066ff}{数据范围与提示}\)

有spj

\(\color{#0066ff}{题解}\)

题意就是求两条不相交的从1-n的路径,使得经过的点尽可能多

所以,若本图合法,则跑完最大流一定\(\leq 2\)

跑完就知道走了哪些点

因为要使路径最长

所以跑费用流,对边赋权为1跑最长路

每个点要拆点,拆成的两个点连权为1的边

s,t作为起点终点,再练一条权为0的边

对于图中所给边,直接连权为0的边就行

最后重新建图,dfs

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<queue>
#include<string>
#define _ 0
#define LL long long
inline LL in()
{
    LL x=0,f=1; char ch;
    while(!isdigit(ch=getchar()))(ch=='-')&&(f=-f);
    while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();
    return x*f;
}
const int inf=0x7fffffff;
int n,v,s,t,cnt=1;
std::queue<int> q;
struct node
{
    int to,dis,nxt,can;
    node(int to=0,int dis=0,int nxt=0,int can=0):to(to),dis(dis),nxt(nxt),can(can){}
}e[1050500];
int dis[1200],change[1200],head[1200],road[1200];
bool vis[1200],flag;
std::map<std::string,int> mp;
std::string f[1200],ss1,ss2;
int aa[1200],bb[1200];
int h[1200],st[1200],top;
inline void add(int from,int to,int dis,int can)
{
    e[++cnt]=node(to,dis,head[from],can);
    head[from]=cnt;
}
inline void link(int from,int to,int dis,int can)
{
    add(from,to,dis,can);
    add(to,from,-dis,0);
}
inline bool spfa()
{
    for(int i=1;i<=n<<1;i++) dis[i]=-inf,change[i]=inf;
    dis[s]=0;
    q.push(s);
    while(!q.empty())
    {
        int tp=q.front(); q.pop();
        vis[tp]=false;
        for(int i=head[tp];i;i=e[i].nxt)
        {
            int go=e[i].to;
            if(dis[go]<dis[tp]+e[i].dis&&e[i].can>0)
            {
                dis[go]=dis[tp]+e[i].dis;
                change[go]=std::min(change[tp],e[i].can);
                road[go]=i;
                if(!vis[go]) vis[go]=true,q.push(go);
            }
        }
    }
    return change[t]!=inf;
}
inline void add(int from,int to)
{
    e[++cnt]=node(to,0,h[from],0);
    h[from]=cnt;
}
inline void dfs(int x)
{
    st[++top]=x;
    vis[x]=1;
    for(int i=h[x];i;i=e[i].nxt)
    {
        int go=e[i].to;
        if(!vis[go]) dfs(go);
    }
}
inline void mcmf()
{
    int flow=0;
    int cost=0;
    while(spfa())
    {
        flow+=change[t];
        cost+=change[t]*dis[t];
        for(int i=t;i!=s;i=e[road[i]^1].to)
        {
            e[road[i]].can-=change[t];
            e[road[i]^1].can+=change[t];
        }
    }
    if(cost==2)
    {
        printf("2\n");
        std::cout<<f[1]<<'\n'<<f[n]<<'\n'<<f[1];
    }
    else if(flow==2)
    {
        printf("%d\n",cost);
        for(int i=1;i<=v;i++)
            for(int j=head[aa[i]+n];j;j=e[j].nxt)
                if(e[j].to==bb[i]&&!e[j].can)
                    add(aa[i],bb[i]),add(bb[i],aa[i]);
        dfs(s);
        for(int i=1;i<=top;i++) std::cout<<f[st[i]]<<'\n';
        std::cout<<f[1];
    }
    else return (void)(printf("No Solution!"));
}
int main()
{
    n=in(),v=in();
    s=1,t=n*2;
    for(int i=1;i<=n;i++)
    {
        std::cin>>f[i];
        mp[f[i]]=i;
        link(i,i+n,1,1);
    }
    link(s,s+n,0,1);
    link(n,n+n,0,1);
    for(int i=1;i<=v;i++)
    {
        std::cin>>ss1>>ss2;
        if(mp[ss1]>mp[ss2]) std::swap(ss1,ss2);
        aa[i]=mp[ss1],bb[i]=mp[ss2];
        link(mp[ss1]+n,mp[ss2],0,1);
    }
    mcmf();
    return 0;
}

原文地址:https://www.cnblogs.com/olinr/p/10105179.html

时间: 2024-10-30 08:13:29

P2770 航空路线问题的相关文章

洛谷 P2770 航空路线问题【最大费用最大流】

记得cnt=1!!因为是无向图所以可以把回来的路看成另一条向东的路.字符串用map处理即可.拆点限制流量,除了1和n是(i,i+n,2)表示可以经过两次,其他点都拆成(i,i+n,1),费用设为1,原图中的边(i,j)连接(i+n,j,1),注意特判掉i==q&&j==nst直接相连的情况,流量要设为2,然后跑最大费用最大流,如果流量小于2就是无解,否则分别从s和tdfs输出方案. 记得输出方案前先输出一次起点. #include<iostream> #include<c

网络流24题-航空路线问题

航空路线问题 时空限制1000ms / 128MB 题目描述 给定一张航空图,图中顶点代表城市,边代表 2 城市间的直通航线.现要求找出一条满足下述限制条件的且途经城市最多的旅行路线. (1)从最西端城市出发,单向从西向东途经若干城市到达最东端城市,然后再单向从东向西飞回起点(可途经若干城市). (2)除起点城市外,任何城市只能访问 1 次. 对于给定的航空图,试设计一个算法找出一条满足要求的最佳航空旅行路线. 输入输出格式 输入格式: 第 1 行有 2 个正整数 N 和 V,N 表示城市数,N

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

Description 给定一张航空图,图中顶点代表城市,边代表2城市间的直通航线.现要求找出一条满足下述限制条件的且途经城市最多的旅行路线. (1)从最西端城市出发,单向从西向东途经若干城市到达最东端城市,然后再单向从东向西飞回起点(可途经若干城市). (2)除起点城市外,任何城市只能访问1次. 对于给定的航空图,试设计一个算法找出一条满足要求的最佳航空旅行路线. Input Format 第1 行有2个正整数N 和V,N 表示城市数,N<100,V 表示直飞航线数.接下来的N行中每一行是一个

航空路线问题(dp解法)

题目链接:https://www.luogu.org/problemnew/show/P2770 题意: 从左到右给你n个点,有m条边连接这些点,问从最左边的点到达最右边的点再回到最左边的点最多可以经过几个点(除了起点外每个点最多只能被经过一次). 题解: 首先,我们可以把题意转化成从最左边的点走两条不相交的路线到达最右边的点,且使经过的点最多.标程是最大费用最大流. 为了限流,我们把每个点i拆成两个点xi,yi,x1->y1.xn->yn连一条容量为2,费用为1的边,其他点xi->yi

【网络流24题】No.11(航空路线问题 最长不相交路径 最大费用流)

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

[网络流24题#11] 航空路线 [网络流,最大权值最大流]

只需要把费用流的Spfa中的小于号改一下就好了,对于题目中要求要飞过去在飞回来,只需要一律把边的方向定为从顶点编号较小的向顶点编号较大的,把顶点1和n的边的容量定为2,其余边为1即可. #include <iostream> #include <algorithm> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <

[luoguP2770] 航空路线问题(最小费用最大流)

传送门 模型 求最长两条不相交路径,用最大费用最大流解决. 实现 为了限制经过次数,将每个点i拆成xi,yi. 1.从xi向yi连一条容量为1,费用为1的有向边(1<i<N), 2.从x1向y1连一条容量为2,费用为1的有向边, 3.从xN向yN连一条容量为2,费用为1的有向边, 4.如果存在边(i,j)(i<j)从yi向xj连一条容量为1,费用为0的有向边. 如果存在边(i,j)(i>j),那么交换i,j,再连边,因为原题是过去再回来,我们要转换成网络流的图,只求起点到终点的最大

[网络流专练6][线性规划与网络流剩余部分题解]

orz"orzGEOTCBRL" 6:lis 给定正整数序列x1 ,…… , xn. (1)计算其最长递增子序列的长度s. (2)计算从给定的序列中最多可取出多少个长度为s的递增子序列. (3)如果允许在取出的序列中多次使用x1和xn,则从给定序列中最多可取出多少个长 度为s的递增子序列.  看到题目就666了,前两问不是经典dp?因为序列是上升的,所以如果在x1前面加一个x1,个数显然多了f[x2][xn][s-1],或者xn后面加一个xn, 一样的……然后发现题意理解错T_T “多

Python 数据图表工具的比较

Python 的科学栈相当成熟,各种应用场景都有相关的模块,包括机器学习和数据分析.数据可视化是发现数据和展示结果的重要一环,只不过过去以来,相对于 R 这样的工具,发展还是落后一些. 幸运的是,过去几年出现了很多新的Python数据可视化库,弥补了一些这方面的差距.matplotlib 已经成为事实上的数据可视化方面最主要的库,此外还有很多其他库,例如vispy,bokeh, seaborn,  pyga, folium 和networkx,这些库有些是构建在 matplotlib 之上,还有