loj2774(基环树DP)

题目链接

https://loj.ac/problem/2774

题解

这题没有想象中那么麻烦。。

首先发现要满足题目要求初始边一定是每个点有且只有一条出边,那么这个图就变成了基环树森林。。

然后考虑树DP的话,显然可以根据当前点的出边有没有改变设状态。再考虑环上的情况,由于只能两两配对,所以能形成配对的只有环上的相邻两点,那么如果在序列上直接DP过去,环上考虑跨环和不跨环,跨环其实就是把头尾配对,然后又变成序列了,所以没什么大碍。。

最后需要特判一下环大小为 2 和 1 的情况,然后就没了。。

讨论基本一次覆盖到,然而还是有地方写挫了。。




代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/**
*         ┏┓    ┏┓
*         ┏┛┗━━━━━━━┛┗━━━┓
*         ┃       ┃  
*         ┃   ━    ┃
*         ┃ >   < ┃
*         ┃       ┃
*         ┃... ⌒ ...  ┃
*         ┃ ┃
*         ┗━┓ ┏━┛
*          ┃ ┃ Code is far away from bug with the animal protecting          
*          ┃ ┃ 神兽保佑,代码无bug
*          ┃ ┃           
*          ┃ ┃       
*          ┃ ┃
*          ┃ ┃           
*          ┃ ┗━━━┓
*          ┃ ┣┓
*          ┃ ┏┛
*          ┗┓┓┏━━━━━━━━┳┓┏┛
*           ┃┫┫ ┃┫┫
*           ┗┻┛ ┗┻┛
*/

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<map>
#include<stack>
#include<cmath>
#include<set>
#include<bitset>
#include<complex>
#include<cstdlib>
#include<assert.h>
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,l,r) for(int i=l;i>=r;i--)
#define link(x) for(edge *j=h[x];j;j=j->next)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define mid (x+y>>1)
#define eps 1e-8
#define succ(x) (1<<x)
#define lowbit(x) (x&(-x))
#define sqr(x) ((x)*(x))
#define NM 100005
#define nm 1000005
using namespace std;
const double pi=acos(-1);
const ll inf=1e9+7;
int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}


struct edge{int t;edge*next;}e[NM],*h[NM],*o=e;
void add(int x,int y){o->t=y;o->next=h[x];h[x]=o++;}
int n,d[NM][2],dp[NM];
bool v[NM];
map<string,int>mp;
int ans;

int low[NM],_x,f[NM],tot,c[NM];
void tar(int x){
low[x]=_x;
link(x)if(low[j->t]==_x)
for(int y=x;y!=f[j->t];y=f[y])c[++tot]=y,v[y]++;
else if(!low[j->t])f[j->t]=x,tar(j->t);
}
void dfs(int x){
int s=0;
v[x]++;
link(x)if(!v[j->t]){
dfs(j->t);
d[x][0]+=d[j->t][1];
s=max(s,d[j->t][1]-d[j->t][0]);
}
d[x][1]=d[x][0]-s+1;
}

int main(){
n=read();
if(n&1)return 0*printf("-1\n");
inc(i,1,n){
string s,t;
cin>>s>>t;
int x=mp.count(s)?mp[s]:mp[s]=++tot;
int y=mp.count(t)?mp[t]:mp[t]=++tot;
if(v[x])return 0*printf("-1\n");
add(y,x);v[x]++;
}
for(auto&j:mp)cout<<j.first<<' '<<j.second<<endl;
mem(v);
inc(k,1,n)if(!low[k]){
tot=0;
tar(_x=k);
inc(i,1,tot)dfs(c[i]);
if(tot==1){
ans+=d[c[1]][1];
}else if(tot==2){
ans+=min(d[c[1]][1]+d[c[2]][1],d[c[1]][0]+d[c[2]][0]);
}
if(tot<=2)continue;
inc(i,1,tot){
dp[i]=dp[i-1]+d[c[i]][1];
if(i>1)dp[i]=min(dp[i],dp[i-2]+d[c[i]][0]+d[c[i-1]][0]+1);
}
tot--;dp[1]=0;
inc(i,2,tot){
dp[i]=dp[i-1]+d[c[i]][1];
if(i>2)dp[i]=min(dp[i],dp[i-2]+d[c[i]][0]+d[c[i-1]][0]+1);
}
ans+=min(dp[tot+1],dp[tot]+d[c[1]][0]+d[c[tot+1]][0]+1);
}
printf("%d\n",ans);
return 0;
}