题目大概说给一个森林求其最小点覆盖数,同时在最小点覆盖条件下输出最多有多少条边被覆盖两次。
- dp[0/1][u]表示以u为根的子树内的边都被覆盖且u不属于/属于覆盖集所需的最少点数
- 另外,用cnt[0/1][u]表示满足dp[0/1][u]状态下子树内被覆盖两次最多的边数
- 对于dp[0][u]只能从其孩子结点v的dp[1][v]转移,而dp[1][u]从dp[0][v]或者dp[1][v]转移,转移时如果同时转移更新cnt的值。。
思路要清晰。。转移细节要注意。。另外注意是森林。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define MAXN 1111 6 7 struct Edge{ 8 int v,next; 9 }edge[MAXN<<1]; 10 int NE,head[MAXN]; 11 void addEdge(int u,int v){ 12 edge[NE].v=v; edge[NE].next=head[u]; 13 head[u]=NE++; 14 } 15 16 int d[2][MAXN],cnt[2][MAXN]; 17 bool vis[MAXN]; 18 void dfs(int u,int fa){ 19 cnt[0][u]=cnt[1][u]=0; 20 d[0][u]=0; 21 d[1][u]=1; 22 vis[u]=1; 23 for(int i=head[u]; i!=-1; i=edge[i].next){ 24 int v=edge[i].v; 25 if(v==fa) continue; 26 dfs(v,u); 27 d[0][u]+=d[1][v]; 28 cnt[0][u]+=cnt[1][v]; 29 if(d[0][v]>d[1][v]){ 30 cnt[1][u]+=cnt[1][v]+1; 31 d[1][u]+=d[1][v]; 32 }else if(d[0][v]<d[1][v]){ 33 cnt[1][u]+=cnt[0][v]; 34 d[1][u]+=d[0][v]; 35 }else{ 36 cnt[1][u]+=max(cnt[0][v],cnt[1][v]+1); 37 d[1][u]+=d[1][v]; 38 } 39 } 40 } 41 42 int main(){ 43 int t,n,m; 44 scanf("%d",&t); 45 for(int cse=1; cse<=t; ++cse){ 46 scanf("%d%d",&n,&m); 47 NE=0; 48 memset(head,-1,sizeof(head)); 49 int a,b; 50 for(int i=0; i<m; ++i){ 51 scanf("%d%d",&a,&b); 52 addEdge(a,b); 53 addEdge(b,a); 54 } 55 memset(vis,0,sizeof(vis)); 56 int res=0,mm=0; 57 for(int i=0; i<n; ++i){ 58 if(!vis[i]){ 59 dfs(i,i); 60 if(d[0][i]>d[1][i]){ 61 res+=d[1][i]; 62 mm+=cnt[1][i]; 63 }else if(d[0][i]<d[1][i]){ 64 res+=d[0][i]; 65 mm+=cnt[0][i]; 66 }else{ 67 res+=d[0][i]; 68 mm+=max(cnt[0][i],cnt[1][i]); 69 } 70 } 71 } 72 printf("Case %d: %d %d %d\n",cse,res,mm,m-mm); 73 } 74 return 0; 75 }
时间: 2024-10-05 23:15:05