您的位置:首页 > 其它

LightOJ1230 Placing Lampposts(DP)

2016-07-14 20:17 302 查看
题目大概说给一个森林求其最小点覆盖数,同时在最小点覆盖条件下输出最多有多少条边被覆盖两次。

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的值。。

思路要清晰。。转移细节要注意。。另外注意是森林。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 1111

struct Edge{
int v,next;
}edge[MAXN<<1];
int NE,head[MAXN];
void addEdge(int u,int v){
edge[NE].v=v; edge[NE].next=head[u];
head[u]=NE++;
}

int d[2][MAXN],cnt[2][MAXN];
bool vis[MAXN];
void dfs(int u,int fa){
cnt[0][u]=cnt[1][u]=0;
d[0][u]=0;
d[1][u]=1;
vis[u]=1;
for(int i=head[u]; i!=-1; i=edge[i].next){
int v=edge[i].v;
if(v==fa) continue;
dfs(v,u);
d[0][u]+=d[1][v];
cnt[0][u]+=cnt[1][v];
if(d[0][v]>d[1][v]){
cnt[1][u]+=cnt[1][v]+1;
d[1][u]+=d[1][v];
}else if(d[0][v]<d[1][v]){
cnt[1][u]+=cnt[0][v];
d[1][u]+=d[0][v];
}else{
cnt[1][u]+=max(cnt[0][v],cnt[1][v]+1);
d[1][u]+=d[1][v];
}
}
}

int main(){
int t,n,m;
scanf("%d",&t);
for(int cse=1; cse<=t; ++cse){
scanf("%d%d",&n,&m);
NE=0;
memset(head,-1,sizeof(head));
int a,b;
for(int i=0; i<m; ++i){
scanf("%d%d",&a,&b);
addEdge(a,b);
addEdge(b,a);
}
memset(vis,0,sizeof(vis));
int res=0,mm=0;
for(int i=0; i<n; ++i){
if(!vis[i]){
dfs(i,i);
if(d[0][i]>d[1][i]){
res+=d[1][i];
mm+=cnt[1][i];
}else if(d[0][i]<d[1][i]){
res+=d[0][i];
mm+=cnt[0][i];
}else{
res+=d[0][i];
mm+=max(cnt[0][i],cnt[1][i]);
}
}
}
printf("Case %d: %d %d %d\n",cse,res,mm,m-mm);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: