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. hdu-4300(kmp或者拓展kmp)

    题意:乱七八糟说了一大堆,就是先给你一个长度26的字符串,对应了abcd....xyz,这是一个密码表.然后给你一个字符串,这个字符串是不完整的(完整的应该是前半部分是加密的,后半部分是解密了的),然 ...

  2. 会话session

    因为因特网HTTP协议的特性,每一次来自于用户浏览器的请求(request)都是无状态的.独立的.通俗地说,就是无法保存用户状态,后台服务器根本就不知道当前请求和以前及以后请求是否来自同一用户.对于静 ...

  3. linux shell系列10 判断某个月中的星期六和星期天

    #!/bin/bashread -p "请输入月份:" month #输入要查找的月份 mon=`date -d "0 month ago" +%m` #计算本 ...

  4. Android中HttpURLConnection对象是怎么生成的

    try { URL mUrl = new URL("https://www.jianshu.com/"); HttpURLConnection http = (HttpURLCon ...

  5. Codeforces1023E Down or Right 【贪心】

    题目分析: 从起点开始询问终点连通性,优先右走.从终点开始询问起点连通性,优先上走. 代码: #include<bits/stdc++.h> using namespace std; in ...

  6. 洛谷P2320鬼谷子的钱袋.

    题目 这个题考察二进制分解. \(Code\) #include <bits/stdc++.h> #pragma GCC optimize(2) #pragma GCC optimize( ...

  7. mysql查询同一个字段下,不同内容的语句

    太久没有用SQL语句都有些忘记了,今天工作中遇到了那就尝试记录一下吧 需求是这样的:想查询同一个字段下,两条指定了不同内容,的其他的值 主要是要想到用where......in 语句如下:select ...

  8. 使用gradle命令代替CUBA Studio,启动项目

    在cuba platform开发中,一开始都会使用CUBA Studio,这是一个脚手架,可以很方便的创建数据表.视图.Bean等.但是有时也会有奇怪的问题,比如不能读取本地maven 仓库,只读取远 ...

  9. kvm 虚拟机XML文件

    <domain type='kvm' id='29'> //domain 是一个所有虚拟机都需要的根元素,它有两个属性, //type定义使用哪个虚拟机管理程序,值可以是:xen.kvm. ...

  10. IHttpHandler处理请求api

    使用IHttpHandler处理请求,实现webapi功能. 研究asp.net管道处理事件后,可用此法实现webapi功能. 测试环境 VS2017 WIN10 IIS10 集成模式 关键接口类两个 ...