hdu3185 Dead Or Alive

本文介绍了一个关于生存资源分配的问题,通过枚举城市顺序并利用二进制操作来确定最大生存人数。具体方法包括使用二进制记录每个城市的限制条件及人群的分配要求,通过递归搜索来找出最优解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Dead Or Alive

Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 69    Accepted Submission(s): 6


Problem Description
Only several people survive after Doomsday, and a small number of cities have not been destroyed. yifenfei wants to arrange these people to live on the available cities.
Now all the people follow yifenfei to pass the cities.
But there are some restrictions on the cities. Some people will die when pass some cities and every city has a population limitation. If people can’t find a city to live after passing all cities they will be dead! So the order of passing the cities is important.
 

Input
The first line an integer T (1<=T<=100) which means the number of test cases.
Each case starts with two integers n and m, which means the number of people and the number of cities. (1<= n <= 31, 1 <= m <= 10)
Second line has m integers, the ith integer Ci means ith city’s population limitation. The cities are ordered from 0 to m-1. (1 <= Ci <= 6)
Then n lines follow. Each line starts with an integer k which means the number of cities this people will die when passing it. Then k integers follow.
 

Output
The maximum number of people can survive!
 

Sample Input

 
23 33 3 21 102 1 23 32 1 22 0 12 0 21 2
 
Sample Output

 
32
 

Source
 

Recommend

lcy   |   We have carefully selected several similar problems for you:   3190  3187  3184  3186  3188 


题解:不知为什么我之前过的人只有四个(有一个提交了2次),而且还是7年以前的。

这题我的算法可能不是正解,跑了7700多毫秒,其余4个人最多只跑了200多毫秒。

我们先枚举所有城市的顺序(用搜索搜出来),这有!m种。先用一个2进制记录下每个城市会死哪些人(用01表示记录即可),记为g[i],在搜索时我们用个2进制记录哪些人一定要放在这个城市前面(如果经过会死亡的话),0表示一定要放在前面,1表示不一定。

然后转移就是 now=la&(~g[i])  (2进制操作)  //la为上一个位置的放置要求,now为这个位置的放置要求。

最后取最小值即可


代码(前面讲的云里雾里的):

#include<bits/stdc++.h>
using namespace std;
int ans,n,m,gg[50],a[50],b[50],c[50];
long long g[50];
void dfs(int x,long long la,int k,int k1,int sum){
	long long now;
	int t1,kk;
	if(x>m){
		if(m-sum-k>0)k+=m-sum-k;
		ans=min(ans,k);
		return;
	}	
	for(int i=0;i<m;i++)
	 if(gg[i]==0){
	 	gg[i]=1;b[x]=i;
		now=la&(~g[i]);
		c[x]=now;
	 	t1=k1-__builtin_popcount(now);
	 	//printf("%d %d\n",i,t1);
	 	//k1:now中1的个数
		//t1:now和la中1相差的个数 
	 	if(n-k1+t1-k>sum){
	 		kk=n-k1+t1-k-sum;
	 		dfs(x+1,now,k+kk,k1-t1,sum+a[i]);
		 }
		  else
	 	dfs(x+1,now,k,k1-t1,sum+a[i]);
	 	gg[i]=0;
	 }
}
int main(){
	int t1,i,j,k1,t;
	scanf("%d",&t1);
	while(t1--){
		memset(gg,0,sizeof(gg));
		memset(g,0,sizeof(g));
		scanf("%d%d",&n,&m);
		ans=n;
		for(i=0;i<m;i++){
			scanf("%d",&a[i]);
		} 
		for(i=1;i<=n;i++){
			scanf("%d",&k1);
			for(j=1;j<=k1;j++){
				scanf("%d",&t);
				g[t]|=1<<(i-1);
			}
		}
		dfs(1,(1<<n)-1,0,n,0);
		printf("%d\n",n-ans);
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值