一题多解——Strategic Game

来源:互联网 发布:淘宝网保健品 编辑:程序博客网 时间:2024/06/15 13:48

点击打开题目

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

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

代码如下:

#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);    }}