基环树上求最大独立边集,且输出方案
题解说最大独立边集的大小可以贪心,但不知所贪
正解是找了个性质
发现在环上任选一条边断掉,如果影响了答案说明这条边一定要选,那和两个端点相连的另外两条边就一定不选
于是可以分别断掉后分别做一次DP,取最大的那个
- 类似 边的最大独立集/需要贪心地选边且边不能相邻/边的选法只有全奇/偶 有性质:若钦定某条边选/不选,那与其相邻的边是否选择就已知了
所以可以分别钦定两条相邻的边,分别求出它们选与不选时的结果,实际上就对应了可行的奇/偶两种可能
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 1000010
#define ll long long
#define fir first
#define sec second
#define make make_pair
#define pb push_back
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n;
namespace force{
bool mp[30][30];
int bel[50], max1, max2;
bool vis[50];
vector<pair<int, int>> v, ans;
void check() {
int cnt1=0, cnt2=0;
for (auto it:v) {
if (mp[it.fir][it.sec] || mp[it.sec][it.fir]) {
++cnt1;
if (bel[it.fir]!=bel[it.sec]) ++cnt2;
}
}
if (cnt1>max1) {
max1=cnt1, max2=cnt2; ans=v;
}
else if (cnt1==max1 && cnt2>max2) {
max1=cnt1, max2=cnt2; ans=v;
}
}
void dfs(int u) {
if (u>n) {check(); return ;}
if (vis[u]) {dfs(u+1); return ;}
vis[u]=1;
for (int i=u+1; i<=n; ++i) if (!vis[i]) {
vis[i]=1; v.push_back(make(u, i));
dfs(u+1);
vis[i]=0; v.pop_back();
}
vis[u]=0;
}
void solve() {
max1=0; max2=0;
memset(mp, 0, sizeof(mp));
memset(bel, 0, sizeof(bel));
memset(vis, 0, sizeof(vis));
v.clear(); ans.clear();
for (int i=1; i<=n; ++i) {
mp[i][read()]=1; bel[i]=read();
}
dfs(1);
printf("%d %d\n", max1, max2);
for (auto it:ans) printf("%d %d\n", it.fir, it.sec);
}
}
namespace task{
int head[N], size, fa[N], back[N], bel[N];
bool ring[N], vis[N], vis2[N];
vector<pair<int, int>> ans2, s1, s2;
struct edge{int to, next; bool back, vis;}e[N<<1];
inline void add(int s, int t, int typ) {e[++size].to=t; e[size].back=typ; e[size].next=head[s]; head[s]=size;}
struct sit{
int fir, sec;
sit(){}
sit(int a, int b):fir(a),sec(b){}
inline void operator = (pair<int, int> p) {fir=p.fir; sec=p.sec;}
inline bool operator < (sit b) {return fir==b.fir?sec<b.sec:fir<b.fir;}
inline sit operator - (sit b) {return sit(fir-b.fir, sec-b.sec);}
inline sit operator + (sit b) {return sit(fir+b.fir, sec+b.sec);}
inline void clear() {fir=0; sec=0;}
}dp[N][2], ans, t1, t2;
inline int find(int p) {return fa[p]==p?p:fa[p]=find(fa[p]);}
int dfs1(int u) {
// cout<<"dfs1: "<<u<<endl;
vis[u]=1;
for (int i=head[u],v; ~i; i=e[i].next) if (!e[i].back) {
v = e[i].to;
if (vis[v]) {ring[u]=1; return v;}
int tem=dfs1(v);
if (~tem) ring[u]=1;
return tem==u?-1:tem;
}
return -1;
}
void dfs2(int u) {
// cout<<"dfs2: "<<u<<endl;
sit dlt(0, 0); int from=-1;
bool leaf=1;
for (int i=head[u],v; ~i; i=e[i].next) if (e[i].back && !e[i].vis) {
v = e[i].to;
dfs2(v); leaf=0;
dp[u][1]=dp[u][1]+dp[v][0];
sit t=dp[v][1]-dp[v][0]+sit(1, bel[v]!=bel[u]);
if (dlt<t) dlt=t, back[u]=v;
}
if (!leaf) dp[u][0]=dp[u][1]+dlt;
// printf("dp[%d][1]=%d,%d\n", u, dp[u][1].fir, dp[u][1].sec);
// printf("dp[%d][0]=%d,%d\n", u, dp[u][0].fir, dp[u][0].sec);
}
void dfs3(int u, vector<pair<int,int>>& v, int lst) {
// cout<<"dfs3: "<<u<<' '<<lst<<endl;
if (lst) v.pb(make(u, lst));
for (int i=head[u]; ~i; i=e[i].next) if (e[i].back && !e[i].vis) {
dfs3(e[i].to, v, lst?0:(e[i].to==back[u]?u:0));
}
}
void solve() {
size=1; ans.clear(); ans2.clear(); t1.clear(); t2.clear();
memset(head, -1, sizeof(head));
memset(vis, 0, sizeof(vis));
memset(vis2, 0, sizeof(vis2));
memset(ring, 0, sizeof(ring));
for (int i=1; i<=n; ++i) fa[i]=i;
for (int i=1,v; i<=n; ++i) {v=read(); add(i, v, 0); add(v, i, 1); bel[i]=read(); fa[find(v)]=find(i);}
// cout<<"bel: "; for (int i=1; i<=n; ++i) cout<<bel[i]<<' '; cout<<endl;
for (int i=1; i<=n; ++i) if (!vis2[find(i)]) {dfs1(i); vis2[find(i)]=1;}
// cout<<"ring: "; for (int i=1; i<=n; ++i) cout<<ring[i]<<' '; cout<<endl;
memset(vis, 0, sizeof(vis));
for (int u=1; u<=n; ++u) if (ring[u] && !vis[find(u)]) {
// cout<<"u: "<<u<<endl;
int e1, e2, v;
s1.clear(); s2.clear();
for (int i=head[u],v; ~i; i=e[i].next) if (!e[i].back && ring[e[i].to]) {e1=i; e[e1].vis=e[e1^1].vis=1; break;}
memset(dp, 0, sizeof(dp)); memset(back, -1, sizeof(back));
// cout<<"e1: "<<e1<<' '<<e[e1].to<<endl;
v=e[e1].to;
dfs2(u); dfs3(u, s1, 0); t1=dp[u][0];
e[e1].vis=e[e1^1].vis=0;
// cout<<"v: "<<v<<endl;
for (int i=head[v]; ~i; i=e[i].next) if (!e[i].back && ring[e[i].to]) {e2=i; e[e2].vis=e[e2^1].vis=1; break;}
memset(dp, 0, sizeof(dp)); memset(back, -1, sizeof(back));
dfs2(v); dfs3(v, s2, 0); t2=dp[v][0];
e[e2].vis=e[e2^1].vis=0;
if (t1<t2) swap(t1, t2), swap(s1, s2);
// cout<<"s1: "; for (auto it:s1) cout<<it.fir<<','<<it.sec<<' '; cout<<endl;
// cout<<"s2: "; for (auto it:s2) cout<<it.fir<<','<<it.sec<<' '; cout<<endl;
ans=ans+t1; for (auto it:s1) ans2.pb(it);
vis[find(u)]=1;
}
printf("%d %d\n", ans.fir, ans.sec);
for (auto it:ans2) printf("%d %d\n", it.fir, it.sec);
// for (int i=1; i<=ans.fir; ++i) puts("0 0");
}
}
signed main()
{
freopen("deskmate.in", "r", stdin);
freopen("deskmate.out", "w", stdout);
int T=read();
while (T--) {
n=read();
// force::solve();
task::solve();
}
return 0;
}