uva 10859 Placing Lampposts

题目大意:

一个森林,将一些点染色,使所有边都只至少有一个端点被染色

使被染色的点尽可能少,在这个前提下,使两端都被染色的边尽可能多

输出染色的点数,两端被染色的边数,一端被染色的边数

思路:

树形dp[i][0/1] 后一维表示它的父亲是否被染色

但是要用到一个骚操作,因为要使两端都被染色的边尽可能多

所以结果ans用tmp*a+b表示,其中b为一端被染色的边,a为灯的个数,tmp为一个很大的数

这样的话使总的ans最小即可,可以很方便的求出灯数和两种要求的边数

具体dp见注释

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstdlib>
 5 #include<cstring>
 6 #include<algorithm>
 7 #include<vector>
 8 #include<queue>
 9 #define inf 2139062143
10 #define ll long long
11 #define MAXN 1100
12 #define tmp 3000
13 using namespace std;
14 inline int read()
15 {
16     int x=0,f=1;char ch=getchar();
17     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
18     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
19     return x*f;
20 }
21 int n,m,dp[MAXN][2],nxt[MAXN*2],fst[MAXN],to[MAXN*2],T,cnt,ans;
22 void add(int u,int v) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v;}
23 int dfs(int x,bool k,int fa)
24 {
25     if(dp[x][k]) return dp[x][k];
26     int res=tmp,t1=0;
27     for(int i=fst[x];i;i=nxt[i])
28         if(to[i]!=fa) res+=dfs(to[i],1,x);//被染色 
29     if(!k&&fa!=-1) res++;//它不是根而且父亲没有被染过,它与它的fa是一条单端边 
30     if(k||fa==-1)//不染x的情况(x为根或x的fa被染)
31     {
32         for(int i=fst[x];i;i=nxt[i])
33             if(to[i]!=fa) t1+=dfs(to[i],0,x);
34         if(fa>0) t1++;//该节点不是树根,它与它的fa是一条单端边 
35         res=min(res,t1);
36     }
37     return dp[x][k]=res;
38 }
39 int main()
40 {
41     T=read();
42     int a,b;
43     while(T--)
44     {
45         memset(fst,0,sizeof(fst));
46         memset(nxt,0,sizeof(nxt));
47         memset(dp,0,sizeof(dp));
48         n=read(),m=read(),ans=cnt=0;
49         for(int i=1;i<=m;i++) {a=read()+1,b=read()+1;add(a,b);add(b,a);}
50         for(int i=1;i<=n;i++) if(!dp[i][0]) ans+=dfs(i,0,-1);
51         printf("%d %d %d\n",ans/tmp,m-ans%tmp,ans%tmp);
52     }
53 }
View Code

 

posted @ 2017-11-30 17:41  jack_yyc  阅读(165)  评论(0编辑  收藏  举报