1 条题解

  • 0
    @ 2025-5-26 22:14:53

    算法思路:树形动态规划(DP)

    关键思想

    • 树形DP:由于组织结构是树形结构,可以通过动态规划递归地计算每个节点的两种状态:
      1. 选当前节点:不能选其直接子节点(上司和员工不能同时选)。
      2. 不选当前节点:可以选择或不选其子节点(需比较子节点的选与不选的最优解)。
    • 唯一性判断:在动态规划过程中,同时记录当前状态的解是否唯一。

    状态定义

    对每个节点 u,定义:

    • dp[u][0]:不选 u 时的最大人数。
    • dp[u][1]:选 u 时的最大人数。
    • sole[u][0]:不选 u 时的解是否唯一。
    • sole[u][1]:选 u 时的解是否唯一。

    状态转移

    1. u
      • 人数:dp[u][1] = 1 + sum(dp[v][0])vu 的子节点)。
      • 唯一性:若任意子节点 vdp[v][0] 不唯一,则 dp[u][1] 不唯一。
    2. 不选 u
      • 人数:dp[u][0] = sum(max(dp[v][0], dp[v][1]))
      • 唯一性:
        • dp[v][0] == dp[v][1],则解不唯一。
        • 若选择较大值的解不唯一,则 dp[u][0] 不唯一。

    算法步骤

    1. 建树:用邻接表存储员工-上司关系。
    2. 动态规划:从根节点(大老板)开始递归计算每个节点的 dpsole
    3. 输出结果:比较根节点的选与不选,输出最大值及其唯一性。

    代码实现(C++)

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int head[210];
    char name1[110],name2[110];
    char name[210][110];
    int cnt,len;
    int max(int a,int b) { return a>b?a:b;}
    class node 
    {
    public:
    	int v,yes,no;
    	bool yessole,nosole;
    	bool tt;
    	bool vis;
    	int next;
    	node()
    	{
    		tt=true;vis=false; yes=1;no=0;
    		yessole=true;nosole=true;
    	}
    };
    int research(char a[])
    {
    	for(int i=1;i<=cnt;i++)
    		if(strcmp(a,name[i])==0)
    			return i;
    	cnt++;
    	strcpy(name[cnt],a);
    	return cnt; 
    }
    void add(int son,int father,node g[])
    {
    	g[++len].v =son;
    	g[len].tt=false;
    	g[len].next =head[father];
    	head[father]=len;
    }
    void DP(int root,node g[])
    {
    	g[root].vis =true;
    	int i,r1=0,r0;
    	for(i=head[root];i;i=g[i].next )
    	{
    		int v=g[i].v ;
    		if(!g[v].vis)
    			DP(v,g);
    		r1+=g[v].no ;
    		if(g[v].nosole ==false)
    			g[root].yessole =false;
    		g[root].no +=max(g[v].yes ,g[v].no );
    		if(g[v].yes ==g[v].no ||(g[v].no>g[v].yes &&g[v].nosole ==false)||(g[v].yes >g[v].no &&g[v].yessole ==false))
    			g[root].nosole =false; 
    	}
    	g[root].yes =r1+1;
    }
    int main()
    {
    	int n;
    	while(1)
    	{
    		cin>>n;
    		if(n==0) break;
    		cnt=1;
    		len=0;
    		node g[10005];
    		memset(head,0,sizeof(head));
    		scanf("%s",&name1);
    		strcpy(name[1] ,name1 );
    		for(int i=1;i<n;i++)
    		{
    			scanf("%s%s",&name1,&name2);
    			int f1=research(name1);
    			int f2=research(name2);
    			add(f1,f2,g);
    		}
    		DP(1,g);
    		if(g[1].no >g[1].yes )
    		{ 
    			printf("%d ",g[1].no );
    			if(g[1].nosole ) printf("Yes/n");
    			else printf("No/n");
    		}
    		else if(g[1].no ==g[1].yes ){
    			printf("%d No/n",g[1].yes );
    		}
    		else 
    		{
    			printf("%d ",g[1].yes );
    			if(g[1].yessole ) printf("Yes/n");
    			else printf("No/n");
    		}
    	}
    	return 0;
    }
    
    • 1

    信息

    ID
    2343
    时间
    1000ms
    内存
    256MiB
    难度
    6
    标签
    递交数
    2
    已通过
    1
    上传者