现在的位置: 首页 > 算法 > 正文

poj2378 Tree Cutting

2019年09月22日 算法 ⁄ 共 1264字 ⁄ 字号 评论关闭
/*
 * poj2378 AC
 *  一次水过。
 *  简单的树状DP,先做一次dfs算出每个结点的子孙结点总数,包括自己,sum[i]。
 *  再做dfs计算删去每个结点x是否满足条件,即满足:
 *   1) 每个结点的所有子结点i的sum[i]是否小于half。
 *   2) 父结点方向上的结点总数,sum[1]-sum[x]是否小于half(1为树的根结点)。
 *  若满足则为一个解,同时计算每个子结点是否满足。
 *  若某结点不满足条件2,那么其子结点一定不满足条件,
 * 因为sum[1]-sum[x]只会递增,而使子结点一定不满足条件2。
 *
 * */
#include<cstdio>
#include<algorithm>
#include<memory.h>
#define N 10010
using namespace std;

int tree[N<<1],head[N<<1],next[N<<1],sum[N+5];
int ans[N],len = 0,half;
bool vis[N];

long dfs_count(int x)
{
    int i;
    sum[x] = 1,vis[x] = true;
    for(i=head[x];i;i=next[i])
       if(!vis[tree[i]]) sum[x] += dfs_count(tree[i]);
    return sum[x];
}

bool dfs_dp(int x)
{
    vis[x] = true;
    if(sum[1]-sum[x]>half) return false; 
    int i,flag = true;
    for(i=head[x];i;i=next[i])
        if(!vis[tree[i]])
        {
           if(dfs_dp(tree[i])) ans[++len] = tree[i];
           if(sum[tree[i]]>half) flag = false; 
        }
    return flag;
} 

int main()
{
    int n,tot,i,j,k;
//    FILE* fin;
//    fin = fopen("d.in","r");
    scanf("%d",&n);
//    fscanf(fin,"%d",&n);
    for(half=n>>1,tot=0,i=1;i<=n-1;i++) {
//        fscanf(fin,"%d%d",&j,&k);
        scanf("%d%d",&j,&k);
        tree[++tot] = k,next[tot] = head[j],head[j] = tot;
        tree[++tot] = j,next[tot] = head[k],head[k] = tot;
    }
    memset(sum,0,sizeof(sum));
    memset(vis,false,sizeof(vis));
    dfs_count(1);

    memset(vis,false,sizeof(vis));
    if(dfs_dp(1)) ans[++len] = 1;
    if(len==0) 
    {
        printf("NONE\n");
        return 0;
    }

    sort(ans+1,ans+len+1);
    for(i=1;i<=len;i++)
        printf("%d\n",ans[i]);
//    fclose(fin);
    return 0;
}

抱歉!评论已关闭.