【問題分析】
最長の2つのばらばらのパスを見つけ、最大コストと最大フローを使用して解決します。
【モデリング方法】
i番目の都市を2つの頂点<ia>、<ib>に分割します。
1.各都市iについて、容量が1でコストが1の有向エッジを(<ia>、<ib>)に接続します。特に(<1.a>、<1.b>)と(<Na >、<Nb>)容量は2に設定されます。
2.都市iとj(j> i)の間にルートがある場合は、容量が1、コストが0の有向エッジを<ib>から<ja>に接続します。
ソース<1.a>からシンク<Nb>への最大コストと最大フローを見つけます。(<1.a>、<1.b>)がいっぱいでない場合、解決策はありません。それ以外の場合、最大コストと最大フロー2であるソリューションがあります。
【モデリング分析】
各ルートは西から東へです。この質問は、ルートグラフで1からNまでの2つのばらばらのパスを見つけて、パスの長さの合計が最大になるように変換できます。ネットワークフローモデルへの変換は、2つの最も長い拡張パスを見つけることです。各都市は1回しか訪問できないため、都市を2点に分割し、容量が1の辺を接続し、コストを1に設定する必要があります。2つのパスが検出されるため、開始点と終了点の内側のエッジ容量を2に設定する必要があります。次に、コストフロー値-2は2つのパスの長さの合計です。容量が2つの辺が2つあり、コストに1が追加されているため、2に減ったのはなぜですか。最大コストと最大フローを見つけた後、(<1.a>、<1.b>)がフルフローでない場合、2(おそらく1または0)のパスが足りないため、解決策はありません。
[問題の別の解決策]
古典的なマルチスレッドの動的プログラミング問題。
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<queue>
#include<map>
using namespace std;
typedef long long ll;
const int N = 500007, M = 500007, INF = 0x3f3f3f3f;
namespace dinic{
const int N = 500007, M = 500007, INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f;
int S, T, n;
int head[N], nex[M], ver[M], tot, cur[N];
ll dist[N], edge[M], cost[M], maxflow, mincost;
bool vis[N];
inline void add(int x, int y, ll z, ll c, bool o = 1){
ver[tot] = y;
edge[tot] = z;
cost[tot] = c;
nex[tot] = head[x];
head[x] = tot ++ ;
if(o)add(y, x, 0, -c, 0);
}
inline bool spfa(){
for(int i = 1; i <= n; ++ i)dist[i] =LINF;
memset(vis, 0, sizeof vis);
queue<int>q;
q.push(S);
dist[S] = 0;
vis[S] = 1;
while(q.size()){
int x = q.front();
q.pop();
vis[x] = 0;
for(int i = head[x]; ~i ;i = nex[i]){
int y = ver[i];
ll z = edge[i], c = cost[i];
if(dist[y] > dist[x] + z && z){
dist[y] = dist[x] + z;
if(!vis[y])
q.push(y), vis[y] = 1;
}
}
}
return dist[T] != LINF;
}
ll dfs(int x, ll flow = LINF){
if(x == T)return flow;
ll ans = 0, k, i;
vis[x] = 1;
for(int i = cur[x]; ~i; i = nex[i]){
int y = ver[i];
ll z = edge[i], c = cost[i];
if(z && dist[y] == dist[x] + c && vis[y]){
k = dfs(y, min(z, flow));
if(!k)dist[y] = LINF;
edge[i] -= k;
edge[i ^ 1] += k;
ans += k, mincost += k * c, flow -= k;
}
vis[x] = 0;
return ans;
}
}
inline void main(){
while(spfa()){
for(int i = 1; i <= n; ++ i)
cur[i] = head[i];
ll now;
while((now = dfs(S)))
maxflow += now;
}
}
inline void init(int _n, int _S, int _T){
n = _n, S = _S, T = _T, tot = 0, maxflow = 0, mincost = 0;
memset(head, -1, sizeof head);
}
}
map<string, int>ip;
bool way[N];
string s[N], ch;
int n, m, S, T;
int x, y;
inline void dfs1(int x){
way[x] = 1;
cout <<s[x - n] << endl;
for(int i = dinic::head[x]; ~i; i = dinic::nex[i]){
int y = dinic::ver[i], z = dinic::edge[i];
if(y <= n && z){
dfs1(y + n);
break;
}
}
}
inline void dfs2(int x){
for(int i = dinic::head[x]; ~i; i = dinic::nex[i]){
int y = dinic::ver[i], z = dinic::edge[i];
if(y <= n && z && !way[y + n])
dfs2(y + n);
}
cout << s[x - n] << endl;
}
int main(){
scanf("%d%d", &n, &m);
S = 1, T = n << 1;
bool flag = 0;
dinic::init(n + n + n, S, T);
for(int i = 1; i <= n; ++ i)
cin >> s[i], ip[s[i]] = i;
//i ~ n 表示入点 n + 1 ~ 2 * n 表示出点
for(int i = 2; i < n; ++ i)
dinic::add(i, n + i, 1, 1);
cout << "ok" << endl;
dinic::add(1, n + 1, 2, 1), dinic::add(n, n + n, 2, 1);
while(m -- ){
cin >> ch, x = ip[ch];
cin >> ch, y = ip[ch];
if(x > y)swap(x, y);
flag |= (x == 1 && y == n);
dinic::add(x + n, y, 1, 0);
}
cout << "ok" << endl;
dinic:main();
cout << "ok" << endl;
if(dinic::maxflow == 2)printf("%d", dinic::mincost - 2);
else if(dinic::maxflow == 1 && flag){
printf("2\n");
cout << s[1] << endl << s[n] <<endl << s[1] << endl;
return 0;
}
else return !printf("No Solution!\n");
for(int i = 1; i <= n + 2; ++ i)
way[i + n] = 0;
dfs1(1 + n), dfs2(1 + n);
}