题意

$n$个点从左向右依次排列,有$m$条双向道路

问从起点到终点,再从终点回到起点,在经过的点不同的情况下最多能经过几个点

Sol

首先,问题可以转化为求两条互不相交的路径,使得点数最多

为了满足流量的限制,肯定会想到拆点,把每个点拆为两个,连流量为$1$,费用为$1$的边

起点和终点连费用为1,流量为2的边

输出方案比较蛋疼,我是dfs两次,然后第二次倒着输出

但是$a->c->a$这种情况会WA,so只好打表喽

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<map>
#include<iostream>
using namespace std;
const int MAXN = 1e4 + , INF = 1e9 + ;
inline int read() {
char c = getchar(); int x = , f = ;
while(c < '' || c > '') {if(c == '-') f = ; c = getchar();}
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x * f;
}
int N, M, S, T;
map<string, int> ID;
map<int, string> nam;
int flag[MAXN];
struct Edge {
int u, v, w, f, nxt, vi;
}E[MAXN];
int head[MAXN], num = ;
inline void add_edge(int x, int y, int w, int f) {
E[num] = (Edge) {x, y, -w, f, head[x], };
head[x] = num++;
}
inline void AddEdge(int x, int y, int w, int f) {
add_edge(x, y, w, f); add_edge(y, x, -w, );
}
int dis[MAXN], vis[MAXN], Pre[MAXN];
bool SPFA() {
memset(dis, 0x3f, sizeof(dis));
memset(vis, , sizeof(vis));
queue<int> q; q.push(S); dis[S] = ;
while(!q.empty()) {
int p = q.front(); q.pop(); vis[p] = ;
for(int i = head[p]; i != -; i = E[i].nxt) {
int to = E[i].v;
if(E[i].f && dis[to] > dis[p] + E[i].w) {
dis[to] = dis[p] + E[i].w; Pre[to] = i;
if(!vis[to]) vis[to] = , q.push(to);
}
}
}
return dis[T] <= INF;
}
int F() {
int flow = INF;
for(int i = T; i != S; i = E[Pre[i]].u) flow = min(flow, E[Pre[i]].f);
for(int i = T; i != S; i = E[Pre[i]].u) E[Pre[i]].f -= flow, E[Pre[i] ^ ].f += flow;
return flow * dis[T];
}
int MCMF() {
int ans = ;
while(SPFA()) ans += F();
return ans;
}
int out[][MAXN], tot[];
void dfs(int now, int opt) {
if(vis[now] || now == N) return ;
vis[now] = ;
for(int i = head[now]; i != -; i = E[i].nxt) {
int to = E[i].v;
if((E[i].u <= N && E[i].v >= N && (E[i].u + N != to)) || (to > N && to - N < out[opt][tot[opt]])) continue;
if(!vis[to] && E[i].f < ) {
E[i].vi = ;
if(to == E[i].u + N) out[opt][++tot[opt]] = E[i].u;
dfs(E[i].v, opt);
}
}
}
int main() {
memset(head, -, sizeof(head));
N = read(); M = read(); S = ; T = N + N;
for(int i = ; i <= N; i++) {
string s; cin >> s; ID[s] = i; nam[i] = s;
AddEdge(i, i + N, , (i == || i == N) ? : );
}
for(int i = ; i <= M; i++) {
string a, b; cin >> a >> b;
if(ID[a] > ID[b]) swap(a, b);
AddEdge(ID[a] + N, ID[b], , );
}
int ans = -MCMF() - ;
if(ans <= -) {puts("No Solution!"); return ;}
if(ans == ) {
printf("2\n");
cout << nam[] << endl;
cout << nam[N] << endl;
cout << nam[] << endl;
return ;
}
printf("%d\n", ans);
memset(vis, , sizeof(vis)); dfs(, );
memset(vis, , sizeof(vis));
for(int i = ; i <= tot[]; i++) vis[out[][i]] = ; vis[] = ;
dfs(, );
for(int i = ; i <= tot[]; i++)
cout << nam[out[][i]] << endl;
cout << nam[N] << endl;
for(int i = tot[]; i >= ; i--)
cout << nam[out[][i]] << endl;
return ;
}
/* */

洛谷P2770 航空路线问题(费用流)的更多相关文章

  1. 洛谷P2770 航空路线问题(费用流)

    传送门 完了这题好厉害……字符串什么的好麻烦…… 要求从$1$到$n$的路径,不重复,经过边数最多 每一个点拆成两个,$A_i,B_i$,然后$A_i$到$B_i$连容量为$1$,费用为$1$的边,保 ...

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

    记得cnt=1!!因为是无向图所以可以把回来的路看成另一条向东的路.字符串用map处理即可.拆点限制流量,除了1和n是(i,i+n,2)表示可以经过两次,其他点都拆成(i,i+n,1),费用设为1,原 ...

  3. 洛谷P2770 航空路线问题 最小费用流

    Code: #include<cstdio> #include<iostream> #include<algorithm> #include<vector&g ...

  4. 洛谷 1004 dp或最大费用流

    思路: dp方法: 设dp[i][j][k][l]为两条没有交叉的路径分别走到(i,j)和(k,l)处最大价值. 则转移方程为 dp[i][j][k][l]=max(dp[i-1][j][k-1][l ...

  5. 洛谷P4003 无限之环(费用流)

    传送门 神仙题啊……不看题解我可能一年都不一定做得出来……FlashHu大佬太强啦 到底是得有怎样的脑回路才能一眼看去就是费用流啊…… 建好图之后套个板子就好了,那么我们着重来讨论一下怎么建图 首先, ...

  6. 洛谷P4012 深海机器人问题(费用流)

    题目描述 深海资源考察探险队的潜艇将到达深海的海底进行科学考察. 潜艇内有多个深海机器人.潜艇到达深海海底后,深海机器人将离开潜艇向预定目标移动. 深海机器人在移动中还必须沿途采集海底生物标本.沿途生 ...

  7. 洛谷P2517 HAOI2010 订货 (费用流)

    标准的费用流问题,关键在于巧妙地建模 一共有n个月份,源点设为0,汇点设为n+1 1.源点向所有月份连边,容量为正无穷,费用为该月进货的费用 2.每个月向下一个月连边,容量为仓库容量,费用为存货费用 ...

  8. 洛谷P4016 负载平衡问题 费用流

    这道题还是很好的. 考察了选手对网络流的理解. 首先,任意两个相邻点之间的运货量时没有限制的. 我们可以将相邻点之间的流量建为无限大,单位费用设为 1,代表运输一个货物需耗费一个代价. 由于题目要求最 ...

  9. 洛谷.1251.餐巾计划问题(费用流SPFA)

    题目链接 /* 每一天的餐巾需求相当于必须遍历某些点若干次 设q[i]为Dayi需求量 (x,y)表示边x容y费 将每个点i拆成i,i',由i'->T连(q[i],0)的边,表示求最大流的话一定 ...

随机推荐

  1. js中一些常见写法的含义

    1. 常见格式:(function() { /* code */ })(); 解释:包围函数(function(){})的第一对括号向脚本返回未命名的函数,随后一对空括号立即执行返回的未命名函数,括号 ...

  2. [RK3288][Android6.0] 调试笔记 --- pmu(rk818)寄存器读写【转】

    本文转载自:http://blog.csdn.net/kris_fei/article/details/76919134 Platform: Rockchip OS: Android 6.0 Kern ...

  3. js截取小数点后面2位

    1.substr var str = "Hello world!"; document.write(str.substr(3)); 输出:lo world! var str = & ...

  4. android按压背景

    android:background="?android:actionBarItemBackground"

  5. 书写优雅的shell脚本(插曲) - kill

    shell之kill.killall.xkill.pkill 2013-01-08 22:03:28|  分类: Linux|举报|字号订阅 1 kill kill的应用是和ps 或pgrep 命令结 ...

  6. 洛谷P2575高手过招——SG函数初试

    题目:https://www.luogu.org/problemnew/show/P2575 第一次用SG函数解决问题,有许多不熟练的地方: 试图按自己的理解写一个dfs,结果错了(连题都没读对,以为 ...

  7. Struts2中的FilterDispatcher和StrutsPrepareAndExecuteFilter的区别

    1.转自:https://blog.csdn.net/zwx521515/article/details/79300453 在Struts2开发中,很多人问到,声明过滤器的时候,为什么有的时候用&qu ...

  8. 6-5 Haar特征2

    在遍历的过程中还需要考虑到一个步长的问题.这个模板一次滑动10个像素,那么总共就需要滑动9次.再加上最开始的第0次,合计在水平方向上和竖直方向上分别都有10个这样的模板,总共也就是100个模板.要计算 ...

  9. 洛谷 - P1434 - 滑雪 - 有向图最长链

    https://www.luogu.org/problemnew/show/P1434 有向图的最长链怎么求?有环肯定不行,这里保证无环.(否则应该使用toposort先求出所有不带环的位置) 设dp ...

  10. 开挂的map

    转自:http://blog.csdn.net/sunshinewave/article/details/8067862 #include<iostream> #include<ma ...