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. 1.ansible基本参数介绍

    想使用ansible 先--help学习下基本的options吧小兄弟1: -m 指定模块名称只有一个模块command 可以省略:-M 指出模块路径来加载2: -a 指定模块参数就是模块的内容你知道 ...

  2. vhdl 边沿

    rising_eage falling_eage clock'event and clock='1' 两种方式

  3. iOS的非常全的三方库,插件,大牛博客

    转自: http://www.cnblogs.com/zyjzyj/p/6015625.html github排名:https://github.com/trending, github搜索:http ...

  4. 洛谷 P1498 南蛮图腾

    题目描述 自从到了南蛮之地,孔明不仅把孟获收拾的服服帖帖,而且还发现了不少少数民族的智慧,他发现少数民族的图腾往往有着一种分形的效果,在得到了酋长的传授后,孔明掌握了不少绘图技术,但唯独不会画他们的图 ...

  5. 自己实现memcpy,strcpy与strncpy

    内存拷贝函数 //实现拷贝不重叠的内存块 void* memcpy1(void* dst,const void* src,size_t count) { char* pTo = (char*)dst; ...

  6. JavaEE进阶集锦(持续更新中)

    1.影响Servlet生命周期的注解:@PostConstruct和@PreDestroy @PostConstruct:被修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器调用一次, ...

  7. A - 敌兵布阵 HDU - 1166 线段树(多点修改当单点修改)

    线段树板子题练手用 #include<cstdio> using namespace std; ; int a[maxn],n; struct Node{ int l,r; long lo ...

  8. Codeforces555 B. Case of Fugitive

    Codeforces题号:#310B 出处: Codeforces 主要算法:贪心+优先队列 难度:4.6 思路分析: 这道题乍一看没有思路…… 考虑贪心的做法.首先预处理出每两座相邻的桥之间边界相差 ...

  9. 初次尝试使用jenkins+python+appium构建自动化测试

    初次尝试使用jenkins+python+appium构建自动化测试 因为刚刚尝试使用jenkins+python+appium尝试,只是一个Demo需要很多完善,先记录一下今天的成果,再接再厉 第一 ...

  10. ramdom 中的 seed 的使用

    实例 1 import ramdom # random.seed(10) # 未加 seed 的时候 for i in range(5): print(random.random()) # 每次输出结 ...