题意:https://codeforces.com/contest/1219/problem/A
每次占一个点,获取一个价值(与该点连通的未占数量),每次选的点必须与占的点相连。
问你最大获益
思路:
树dp出以某个树开始往环上走。
然后就开始考虑环我们怎么走,首先我想的是枚举以那颗树为起点,每次走一个相邻最小的(用优先队列)贪心,但是有100 1 1 1 1 1 50 50 50这种样例
所以就是整体考虑,简单区间dp(n方完成)
1 class mymap 2 { 3 public: 4 int tot,cnt_loop; 5 int head[N],in[N],loop[N],SZ[N]; 6 int ele[N]; 7 int ans[N];//start 8 bool is[N],vis[N];//vis是获取按顺序的循环用 9 struct 10 { 11 int to,next,dis; 12 }edge[N*2]; 13 void Init(int n) 14 { 15 tot=cnt_loop=0; 16 for(int i=0;i<=n;++i) 17 head[i]=in[i]=vis[i]=0,is[i]=1; 18 } 19 void add(int from,int to) 20 { 21 ++tot; 22 edge[tot].to=to; 23 // edge[tot].dis=dis; 24 edge[tot].next=head[from]; 25 head[from]=tot; 26 } 27 void get_loop(int n) 28 { 29 queue<int>q; 30 for(int i=1;i<=n;++i) 31 if(in[i]==1) 32 q.push(i); 33 while(!q.empty()) 34 { 35 int now=q.front();q.pop(); 36 is[now]=0; 37 for(int i=head[now];i;i=edge[i].next) 38 { 39 int to=edge[i].to; 40 in[to]--; 41 if(in[to]==1) 42 q.push(to); 43 } 44 } 45 for(int i=1;i<=n;++i) 46 { 47 if(is[i]) 48 { 49 q.push(i); 50 while(!q.empty()) 51 { 52 int now=q.front();q.pop(); 53 loop[++cnt_loop]=now; 54 vis[now]=1; 55 bool have=0; 56 for(int j=head[now];j;j=edge[j].next) 57 { 58 int to=edge[j].to; 59 if(have)break; 60 if(is[to]&&!vis[to]) 61 { 62 have=1; 63 q.push(to); 64 } 65 } 66 } 67 break; 68 } 69 } 70 } 71 void dfs1(int u,int fa) 72 { 73 SZ[u]=1; 74 for(int i=head[u];i;i=edge[i].next) 75 { 76 int to=edge[i].to; 77 if(to!=fa&&!is[to]) 78 { 79 dfs1(to,u); 80 SZ[u]+=SZ[to]; 81 ele[u]+=ele[to]; 82 } 83 } 84 ele[u]+=SZ[u]; 85 } 86 void dfs2(int u,int fa,int dep,int root,int id,int n) 87 { 88 ans[id]=max(ans[id],ele[u]+dep*(n-SZ[root])); 89 for(int i=head[u];i;i=edge[i].next) 90 { 91 int to=edge[i].to; 92 if(to!=fa&&!is[to]) 93 { 94 // ele[to]=ele[u]-SZ[root]-SZ[to]+SZ[root]+SZ[root]-SZ[to]; 95 ele[to]=ele[u]-SZ[to]+SZ[root]-SZ[to]; 96 dfs2(to,u,dep+1,root,id,n); 97 } 98 } 99 } 100 }TREE; 101 int realPos(int now,int len) 102 { 103 if(now>len) 104 now-=len; 105 else if(now<1) 106 now+=len; 107 return now; 108 } 109 110 int dp1[N][2]; 111 int dp2[N][2]; 112 113 int32_t main() 114 { 115 // freopen("C:\\Users\\13606\\Desktop\\1.txt","r",stdin); 116 int n; 117 sc("%d",&n); 118 TREE.Init(n); 119 for(int i=1;i<=n;++i) 120 { 121 int u,v; 122 sc("%d%d",&u,&v); 123 u++;v++; 124 TREE.add(u,v); 125 TREE.add(v,u); 126 TREE.in[u]++; 127 TREE.in[v]++; 128 } 129 TREE.get_loop(n); 130 for(int i=1;i<=TREE.cnt_loop;++i) 131 { 132 TREE.dfs1(TREE.loop[i],-1); 133 TREE.dfs2(TREE.loop[i],-1,1,TREE.loop[i],i,n); 134 } 135 /* int sum=0; 136 for(int i=1;i<=TREE.cnt_loop;++i) 137 { 138 // pr("%d\n",TREE.ele[TREE.loop[i]]); 139 sum+=TREE.ele[TREE.loop[i]]; 140 }*/ 141 for(int i=1;i<=TREE.cnt_loop;++i)dp1[i][0]=TREE.ans[i],dp2[i][0]=TREE.SZ[TREE.loop[i]]; 142 int LEN=TREE.cnt_loop; 143 int ANS=0; 144 for(int len=2;len<=LEN;++len) 145 { 146 for(int i=1;i<=LEN;++i) 147 { 148 // int xx=realPos(i+1,LEN); 149 // int yy=realPos(i+len-1,LEN); 150 dp1[i][1]=max(dp1[realPos(i+1,LEN)][0]+n-dp2[realPos(i+1,LEN)][0]+TREE.ele[TREE.loop[i]]-TREE.SZ[TREE.loop[i]] 151 ,dp1[i][0]+n-dp2[i][0]+TREE.ele[TREE.loop[realPos(i+len-1,LEN)]]-TREE.SZ[TREE.loop[realPos(i+len-1,LEN)]]); 152 dp2[i][1]=dp2[realPos(i+1,LEN)][0]+TREE.SZ[TREE.loop[i]]; 153 // if(dp[xx][0].second+TREE.SZ[TREE.loop[i]]!=dp[i][0].second+TREE.SZ[TREE.loop[yy]]) 154 // pr("NONONO\n"); 155 if(len==LEN) 156 ANS=max(ANS,dp1[i][1]); 157 } 158 for(int i=1;i<=LEN;++i) 159 dp1[i][0]=dp1[i][1],dp2[i][0]=dp2[i][1]; 160 } 161 pr("%d\n",ANS); 162 return 0; 163 }