一题多解——Strategic Game

点击打开题目

题目大意:给定一棵无根树,点亮其中某些点,使得这棵树的所有边都连接着一个以上的点亮的点

贪心中比较有挑战的题
由于如果点亮叶节点,就只会照亮一条边,但点亮它的父亲,就可以照亮除此边以外的更多的边,所以,可先将所有叶节点的父亲点亮
其余的点,则通过后序遍历来访问,如果它的所有儿子都点亮了,那它就不用点亮,反之则点亮它,最后在搜索出所有点亮的点的数量即可

代码如下:

#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
",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
",ans);
    }
}
原文地址:https://www.cnblogs.com/Darknesses/p/12002553.html