https://www.luogu.org/problemnew/show/P2770

第一眼看过去,觉得这不是一个经典的双路DP模型吗,将一条过去一条回来互不相交的路径看作是起点出发了两条路径一起走向终点,用DP[i][j]表示一条路到i一条路到j的状态下经过的最大的城市,只要保证枚举的城市单调递增,一个n3 的DP就可以直接递推出答案,比较麻烦的是输出路径,开始使用记忆路径的操作但是总是蜜汁WA,后来直接在dp的过程中记录当前状态的前驱就可以了。

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define For(i, x, y) for(int i=x;i<=y;i++)
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x);
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
int read(){int x = ,f = ;char c = getchar();while (c<'' || c>''){if (c == '-') f = -;c = getchar();}
while (c >= ''&&c <= ''){x = x * + c - '';c = getchar();}return x*f;}
const double eps = 1e-;
const int maxn = ;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + ;
int N,M,K;
string name[maxn];
map<string,int>P;
int MAP[maxn][maxn];
int ans[][maxn];
int cnt1,cnt2;
int dp[maxn][maxn];
PII pre[maxn][maxn];
void out(int l,int r){
if(l == && r == ) return;
out(pre[l][r].fi,pre[l][r].se);
if(pre[l][r].fi == l) ans[][++cnt1] = r;
else ans[][++cnt2] = l;
}
int main(){
Sca2(N,M); Mem(MAP,);
for(int i = ; i <= N ; i ++){
cin >> name[i];
P[name[i]] = i;
}
for(int i = ; i <= M ; i ++){
string a,b;
cin >> a >> b;
MAP[P[a]][P[b]] = MAP[P[b]][P[a]] = ;
}
if(N == ){
puts("");
cout << name[] << endl;
return ;
}
Mem(dp,-0x3f);
dp[][] = ;
for(int i = ; i <= N; i ++){
for(int j = ; j < i; j ++){
for(int k = ; k < i ; k ++){
if(MAP[j][i] && dp[j][k] + > dp[i][k]){
dp[i][k] = dp[j][k] + ;
pre[i][k] = mp(j,k);
}
if(MAP[k][i] && dp[j][k] + > dp[j][i]){
dp[j][i] = dp[j][k] + ;
pre[j][i] = mp(j,k);
}
}
}
}
int Ans = -INF;
for(int i = ; i <= N - ; i ++){
if(MAP[N][i]) Ans = max(dp[i][N],Ans);
}
if(Ans <= ){
puts("No Solution!");
return ;
}
Pri(Ans);
for(int i = N - ; i >= ; i --){
if(MAP[N][i] && dp[i][N] == Ans){
out(i,N);
break;
}
}
if(ans[][] != ) cout << name[] << endl;
for(int i = ; i <= cnt1; i ++) cout << name[ans[][i]] << endl;
for(int i = cnt2; i >= ; i --) cout << name[ans[][i]] << endl;
if(ans[][] != ) cout << name[] << endl;
return ;
}

DP

做完了发现这是一道网络流专题里面的题目,想了想还真是。

相当于两条不同的水流同时流向终点,需要保证的是最大流的流量是2,其次除了起点每个点只能流通一次,解决的方法就是将每个点拆点成为i 和i + N,在他们之间建立一条容量为1的边,同时i为入点i + N为出点,保证每个点只能被经过一次,问题在于这题要求的是最多的经过的城市,这种要求两个信息的题粗略估计一下单纯的最大流做不了,是需要用到费用流的,给每个点i 到 i + N的边加上一个-1的cost,就可以用费用流直接维护出最多的城市了,方案的话相当于两遍dfs,搜索两条到终点的路径。

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define For(i, x, y) for(int i=x;i<=y;i++)
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x);
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
int read(){int x = ,f = ;char c = getchar();while (c<'' || c>''){if (c == '-') f = -;c = getchar();}
while (c >= ''&&c <= ''){x = x * + c - '';c = getchar();}return x*f;}
const double eps = 1e-;
const int maxn = ;
const int maxm = ;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + ;
int N,M,K;
string name[maxn];
map<string,int>P;
struct Edge{
int to,nxt,cap,flow,cost;
Edge(){}
Edge(int to,int nxt,int cap,int flow,int cost):to(to),nxt(nxt),cap(cap),flow(flow),cost(cost){}
}edge[maxm * ];
int n;
int head[maxn],tot;
void init(int x){
n = x;
for(int i = ; i <= n; i ++) head[i] = -;
}
void add(int u,int v,int w,int cost){
edge[tot] = Edge(v,head[u],w,,cost);
head[u] = tot++;
edge[tot] = Edge(u,head[v],,,-cost);
head[v] = tot++;
}
int dis[maxn],vis[maxn],pre[maxn];
bool spfa(int s,int t){
for(int i = ; i <= n; i ++) dis[i] = INF,vis[i] = ,pre[i] = -;
dis[s] = ;
queue<int>Q; Q.push(s);
while(!Q.empty()){
int u = Q.front(); Q.pop();
vis[u] = ;
for(int i = head[u]; ~i ; i = edge[i].nxt){
int v = edge[i].to;
if(edge[i].cap <= edge[i].flow) continue;
if(dis[v] > dis[u] + edge[i].cost){
dis[v] = dis[u] + edge[i].cost;
pre[v] = i;
if(!vis[v]){
vis[v] = ;
Q.push(v);
}
}
}
}
return ~pre[t];
}
int mcmf(int s,int t,int &cost){
cost = ;
int flow = ;
while(spfa(s,t)){
int Min = INF;
for(int i = pre[t]; ~i; i = pre[edge[i ^ ].to]){
Min = min(Min,edge[i].cap - edge[i].flow);
}
flow += Min;
for(int i = pre[t]; ~i ; i = pre[edge[i ^ ].to]){
edge[i].flow += Min;
edge[i ^ ].flow -= Min;
cost += Min * edge[i].cost;
}
}
return flow;
}
void dfs1(int t){
cout << name[t] << endl;
if(t == N) return;
t += N;
for(int i = head[t]; ~i ; i = edge[i].nxt){
int v = edge[i].to;
if(edge[i].flow >= ){
edge[i].flow -= ;
edge[i ^ ].flow += ;
dfs1(v);
return;
}
}
}
void dfs2(int t){
if(t == N) return;
t += N;
for(int i = head[t]; ~i ; i = edge[i].nxt){
int v = edge[i].to;
if(edge[i].flow >= ){
edge[i].flow -= ;
edge[i ^ ].flow += ;
dfs2(v);
cout << name[t - N] << endl;
return;
}
}
}
void show(){
dfs1();
dfs2();
}
int main(){
Sca2(N,M);
int S = * N + ,T = * N + ;
init(T);
for(int i = ; i <= N ; i ++){
cin >> name[i]; P[name[i]] = i;
add(i,i + N,,-);
}
add(, + N,,);
add(N,N + N,,);
add(S,,INF,); add(N + N,T,INF,);
for(int i = ; i <= M ; i ++){
string a,b;
cin >> a >> b;
int u = P[a],v = P[b];
if(u > v) swap(u,v);
add(u + N,v,INF,);
}
int cost;
if(mcmf(S,T,cost) != ){
puts("No Solution!");
}else{
Pri(-cost);
show();
}
return ;
}

洛谷P2770 双路DP // 网络流的更多相关文章

  1. Codevs 1427 特种部队(双路DP)

    1427 特种部队 时间限制: 1 s 空间限制: 64000 KB 题目等级 : 黄金 Gold 题目描述 Description 某特种部队接到一个任务,需要潜入一个仓库.该部队士兵分为两路,第一 ...

  2. 洛谷P1155 双栈排序题解(图论模型转换+二分图染色+栈)

    洛谷P1155 双栈排序题解(图论模型转换+二分图染色+栈) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/1311990 原题地址:洛谷P1155 双栈排序 ...

  3. 洛谷P2402 奶牛隐藏(网络流,二分答案,Floyd)

    洛谷题目传送门 了解网络流和dinic算法请点这里(感谢SYCstudio) 题目 题目背景 这本是一个非常简单的问题,然而奶牛们由于下雨已经非常混乱,无法完成这一计算,于是这个任务就交给了你.(奶牛 ...

  4. 洛谷P1108 低价购买[DP | LIS方案数]

    题目描述 “低价购买”这条建议是在奶牛股票市场取得成功的一半规则.要想被认为是伟大的投资者,你必须遵循以下的问题建议:“低价购买:再低价购买”.每次你购买一支股票,你必须用低于你上次购买它的价格购买它 ...

  5. NOIP2017提高组Day2T2 宝藏 洛谷P3959 状压dp

    原文链接https://www.cnblogs.com/zhouzhendong/p/9261079.html 题目传送门 - 洛谷P3959 题目传送门 - Vijos P2032 题意 给定一个 ...

  6. 洛谷P1244 青蛙过河 DP/思路

    又是一道奇奇怪怪的DP(其实是思路题). 原文戳>>https://www.luogu.org/problem/show?pid=1244<< 这题的意思给的挺模糊,需要一定的 ...

  7. 洛谷P3928 Sequence2(dp,线段树)

    题目链接: 洛谷 题目大意在描述底下有.此处不赘述. 明显是个类似于LIS的dp. 令 $dp[i][j]$ 表示: $j=1$ 时表示已经处理了 $i$ 个数,上一个选的数来自序列 $A[0]$ 的 ...

  8. 洛谷P1140 相似基因 (DP)

    洛谷P1140 相似基因 题目背景 大家都知道,基因可以看作一个碱基对序列.它包含了44种核苷酸,简记作A,C,G,TA,C,G,T.生物学家正致力于寻找人类基因的功能,以利用于诊断疾病和发明药物. ...

  9. 洛谷P2224 [HNOI2001] 产品加工 [DP补完计划,背包]

    题目传送门 产品加工 题目描述 某加工厂有A.B两台机器,来加工的产品可以由其中任何一台机器完成,或者两台机器共同完成.由于受到机器性能和产品特性的限制,不同的机器加工同一产品所需的时间会不同,若同时 ...

随机推荐

  1. Express学习(2) ------ 中间件

    TJ Holowaychuck 将 “中间件”描述为易于挂载和调用的模块,可以“无序”使用,并有利于应用的快速开发. 1, 中间件是一个模块.在js中,模块意味着函数,所以中间件是一个函数.那么这个函 ...

  2. hdu-3374(kmp+最小表示法)

    题意:给你一个字符串,这个字符串我们可以把把他变成n个字符串按照以下规则:将当前字符串第一个放到字符串最后一位,字符串的下标依次向前推一位,比如:s[1] s[2 ]s[3] s[4]->s[2 ...

  3. Spring 使用介绍(七)—— Spring事务

    一.数据库事务概述 1.基本介绍 事务必需满足ACID(原子性.一致性.隔离性和持久性)特性,缺一不可: 原子性(Atomicity):即事务是不可分割的最小工作单元,事务内的操作要么全做,要么全不做 ...

  4. fiddler软件测试——Fiddler抓取https设置详解(图文)

    强烈推荐(原创亲测)!!!Fiddler抓取https设置详解(图文)转 本文主要说明了自己在设置fiddler抓取https过程中所遇到的问题及解决步骤,特别是fiddler在设置证书的环节遇到的各 ...

  5. [NOIP2017] 逛公园 【最短路】【强连通分量】

    题目分析: 首先考虑无数条的情况.出现这种情况一定是一条合法路径经过了$ 0 $环中的点.那么预先判出$ 0 $环中的点和其与$ 1 $和$ n $的距离.加起来若离最短路径不超过$ k $则输出$ ...

  6. Appium-desktop安装启用Inspector一直报错An unknown server-side error occurred...

    遇到的问题是: 启用Appium-desktop的Inspector一直报错:An unknown server-side error occurred while processing the co ...

  7. python学习日记(迭代器、生成器)-乱七八糟

    迭代器 迭代是Python最强大的功能之一,是访问集合元素的一种方式. 迭代器是一个可以记住遍历的位置的对象. 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退 ...

  8. 用Python爬取"王者农药"英雄皮肤 原

    padding: 10px; border-bottom: 1px solid #d3d3d3; background-color: #2e8b57; } .second-menu-item { pa ...

  9. c# double decimal

    两种类型 double范围比decimal大,精度比之低 类型 大致范围 精度 .NET Framework 类型 double ±5.0 × 10−324 到 ±1.7 × 10308 15 到 1 ...

  10. 简单使用TFS管理源代码

    今天研究使用了一下TFS,主要是想管理源代码.不涉汲团队管理. 使用环境W10专业版  / VS2017 社区版 / SQLSERVER2016  / TFS2017 EXPRESS版本 1.下载和安 ...