题目大意:给定一棵无根树,点亮其中某些点,使得这棵树的所有边都连接着一个以上的点亮的点
贪心中比较有挑战的题
由于如果点亮叶节点,就只会照亮一条边,但点亮它的父亲,就可以照亮除此边以外的更多的边,所以,可先将所有叶节点的父亲点亮
其余的点,则通过后序遍历来访问,如果它的所有儿子都点亮了,那它就不用点亮,反之则点亮它,最后在搜索出所有点亮的点的数量即可
代码如下:
#include <cstdio>
#include<cmath>
#include <cstring>
#include <algorithm>
using namespace std;
int fir[3001],nxt[3001],to[3001],cnt;
bool vis[1501],lt[1501];
int getint()
{
int num=0,flag=1;char c;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
return num*flag;
}
void newnote(int u,int v){to[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt;}
int n,ans;
void dfs(int x)
{
int i;
for(i=fir[x];i;i=nxt[i])
if(!vis[to[i]])
{
vis[to[i]]=1;
dfs(to[i]);
if(!lt[to[i]])lt[x]=1;
}
}
int main()
{
int i,j,x,y;
while(scanf("%d",&n)==1)
{
ans=cnt=0;
memset(fir,0,sizeof fir);memset(to,0,sizeof to);memset(nxt,0,sizeof nxt);
memset(vis,0,sizeof vis);memset(lt,0,sizeof lt);
for(i=1;i<=n;i++)
{
x=getint()+1;j=getint();
while(j--)y=getint()+1,newnote(x,y),newnote(y,x);
}
dfs(1);
for(i=1;i<=n;i++)if(lt[i])ans++;
printf("%d\n",ans);
}
}
如果没有yy到这种方法,树形DP也可以
设dp[root][0]
为没有点亮,dp[root][1]
为点亮
状态转移方程如下:
dp[root][0]+=dp[son[root][i]][1];
dp[root][1]+=min(dp[son[root][i]][0],dp[son[root][i]][1]);
代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int dp[1501][2],son[1500][1500],fa[1501];
int min(int x,int y){return x<y?x:y;}
int getint()
{
char c;int flag=1,num=0;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
return num*=flag;
}
void work(int root)
{
int i;
for(i=1;i<=son[root][0];i++)
{
work(son[root][i]);
dp[root][0]+=dp[son[root][i]][1];
dp[root][1]+=min(dp[son[root][i]][0],dp[son[root][i]][1]);
}
dp[root][1]++;
}
int n;
int main()
{
int i,j,x,y,z;
n=getint();
for(i=1;i<=n;i++)
{
x=getint(),x++,y=getint();
for(j=1;j<=y;j++)
{
z=getint(),z++;
son[x][++son[x][0]]=z;
fa[z]=x;
}
}
for(i=1;i<=n;i++)
if(!fa[i])
{
work(i);
printf("%d",min(dp[i][0],dp[i][1]));
}
}
DP也yy不到?看二分图匹配能不能救你
代码如下:
#include <cstdio>
#include<cmath>
#include <cstring>
#include <algorithm>
using namespace std;
int fir[3001],nxt[3001],to[3001],cnt;
bool vis[1501],vy[3001];
int linky[3001],X[1501],g;
int getint()
{
int num=0,flag=1;char c;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
return num*flag;
}
void newnote(int u,int v){to[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt;}
int n,ans;
void dfs(int u,int deep)
{
int i;
if(deep&1)X[++g]=u;
for(i=fir[u];i;i=nxt[i])
if(!vis[to[i]])
{
vis[to[i]]=1;
dfs(to[i],deep+1);
}
}
bool xyl(int x)
{
int i;
for(i=fir[x];i;i=nxt[i])
if(!vy[to[i]])
{
vy[to[i]]=1;
if(!linky[to[i]]||xyl(linky[to[i]]))
{
linky[to[i]]=x;return 1;
}
}
return 0;
}
int main()
{
int i,j,x,y;
while(scanf("%d",&n)==1)
{
ans=cnt=g=0;
memset(fir,0,sizeof fir);memset(to,0,sizeof to);memset(nxt,0,sizeof nxt);
memset(vis,0,sizeof vis);memset(linky,0,sizeof linky);
for(i=1;i<=n;i++)
{
x=getint()+1;j=getint();
while(j--)y=getint()+1,newnote(x,y),newnote(y,x);
}
vis[1]=1;dfs(1,1);
for(i=1;i<=g;i++)
{
memset(vy,0,sizeof vy);
ans+=xyl(X[i]);
}
printf("%d\n",ans);
}
}