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. Random Processes

    对于信号处理来说,有一类信号是非常重要的,这类信号就是随机信号(random signal),也被称为随机过程(random processes/stochastic processes).在各种书籍 ...

  2. Android系统启动概要

    注:Java系统服务与本地系统服务标注反了 1.Linux内核 Android系统启动时,首先通过BootLoader(系统加载器)加载Linux内核,在Linux加载启动时,首先初始化内核,再调用i ...

  3. Keepalived+Haproxy高可用负载均衡群集

    介绍 HAProxy提供高可用性.负载均衡以及基于TCP和HTTP应用的代理,支持虚拟主机,它是免费.快速并且可靠的一种解决方案.HAProxy特别适用于那些负载特大的web站点,这些站点通常又需要会 ...

  4. linux-shell系列6-rundeck生成host文件

    nmap -sP 192.168.30.* -PS22 -oG nmap.out && awk '/Status: Up/ {print $2}' nmap.out > /tmp ...

  5. [Codeforces741D]Arpa's letter-marked tree and Mehrdad's Dokhtar-kosh paths——dsu on tree

    题目链接: Codeforces741D 题目大意:给出一棵树,根为$1$,每条边有一个$a-v$的小写字母,求每个点子树中的一条最长的简单路径使得这条路径上的边上的字母重排后是一个回文串. 显然如果 ...

  6. kibana get 查询失效

    kibana版本:5.4 在使用kibana 查询数据时,如果我们根据数据id 来获得一条数据,写法 get 索引名称/类型名称/文档主键 如:get testindex/testtype/01 这样 ...

  7. UOJ273 [清华集训2016] 你的生命已如风中残烛 【数学】

    题目分析: 把$0$卡牌看成$-1$.题目要求前缀和始终大于等于$1$. 最后添加一个$-1$,这样除了最后一位之外大于等于1,最后一位等于0. 构造圆排列.这样的话一个圆排列只有一个满足的情况,然后 ...

  8. 【XSY1162】鬼计之夜 最短路

    题目描述 给你一个\(n\)个点\(m\)条边的有向图,有\(k\)个关键点.求一条最短的从一个关键点到另一个关键点的路径. \(n,m,k\leq 100000\) 题解 跑\(k^2\)次最短路显 ...

  9. MT【256】2016四川高考解答压轴题

    (2016四川高考数学解答压轴题)设函数$f(x)=ax^2-a-\ln x,a\in R$. 1)讨论$f(x)$的单调性;2)确定$a$的所有可能值,使得$f(x)>\dfrac{1}{x} ...

  10. Number Cutting Game HDU - 2848(DFS)

    两个对于一个数切割 k 次,然后切割以后把这些值加起来,然后继续切割 k 次,问谁先没有办法切割. 对于第一个人,先枚举每种切割的情况,然后拿去给第二个人切割,如果第二个人怎么样都没办法切割出来,那么 ...