zoukankan      html  css  js  c++  java
  • 【t064】最勇敢的机器人

    Time Limit: 1 second
    Memory Limit: 128 MB

    【问题描述】

    【背景】
    Wind设计了很多机器人。但是它们都认为自己是最强的,于是,一场比赛开始了~
    【问题描述】
    机器人们都想知道谁是最勇敢的,于是它们比赛搬运一些物品。
    它们到了一个仓库,里面有n个物品,每个物品都有一个价值Pi和重量Wi,但是有些物品放在一起会爆炸,并且爆炸具有传递性。
    (a和b会爆炸、b和c会爆炸则a和c会爆炸)机器人们可不想因此损失自己好不容易从Wind那里敲诈来的装备,于是它们想知道在
    能力范围内,它们最多可以拿多少价值的物品。
    你能帮助它们吗? 

    【输入格式】

    每组测试数据
    第1行为n,Wmax,k(0<=n,Wmax,k<=1000)
    接下来n行,为每个物品的Pi,Wi(0<=Pi<=1000,1<=Wi<=10,均为整数)
    再接下来k行,每行2个数字a,b表示a和b会发生爆炸 

    【输出格式】

    对每组数据输出1行
    为最大可能价值 

    Sample Input

    3 10 1
    100 1
    200 5
    10 5
    1 2 
    
    
    
    

    Sample Output

       210

    【题解】

    a和b会发生爆炸。即a,b中只能选一个。也即分组背包问题。

    首先,如果x和y会发生爆炸就把x和y合并在一起(并查集),然后根据合并的情况构造出k组物品。每组中都只能选取一个物品。

    然后先for k组背包。表示按照组的顺序进行背包的操作。

    然后是for 容量。表示接下来为j容量选取一个物品。

    然后是for第k组物品中的具体每一个物品。

    因为先for的是容量。所以可以保证。只会选取第k组物品中的一个物品。

    最后输出答案即可。

    【代码】

    #include <cstdio>
    
    int fa[1001],n,wmax,k,c[1001],w[1001],f[1001],next[1001],first[1001],what[1001],num = 0;
    
    int findfather(int x) //用来寻找根节点,同时路径压缩 
    {
    	if (fa[x] != x)
    		fa[x] = findfather(fa[x]);
    	return fa[x];
    }
    
    int main()
    {
    	//freopen("F:\rush.txt","r",stdin);
    	scanf("%d%d%d",&n,&wmax,&k);
    	for (int i = 1;i <= n;i++)
    		scanf("%d%d",&c[i],&w[i]);
    	for (int i = 1;i <= n;i++) //并查集数组初始化操作 
    		fa[i] = i;
    	for (int i = 1;i <= k;i++) //输入k个抵触关系 
    		{
    			int x,y;
    			scanf("%d%d",&x,&y);
    			int r1 = findfather(x),r2 = findfather(y);
    			if (r1 != r2) //把这两个物品合并在一起,即同一组物品 
    				fa[r2] = r1;
    		}
    	for (int i = 1;i <= n;i++) //把所有的子节点指向根节点 
    		findfather(i);
    	int bo[1001] = {0}; //用来标记某一个物品是哪一组的物品 
    	k = 0;
    	for (int i =1;i <= n;i++)
    		if (bo[fa[i]] == 0) //这是第一次出现第k组物品的处理方法 
    			{	
    				k++;
    				bo[fa[i]] = k;
    				num++;
    				next[num] = first[k]; //这里用了邻接表来记录k组物品的每一个物品 为了省空间 
    				what[num] = i;
    				first[k] = num;
    			}
    				else //不是第一次出现则记录就好 可以缩短代码。。想缩短就缩吧。-> 邻接表那段可以不用写两次 
    					{
    						num++;
    						next[num] = first[bo[fa[i]]];
    						what[num] = i;
    						first[bo[fa[i]]] = num; 	
    					}
    	for (int i = 1;i <= k;i++) //进行分组背包的操作 
    		for (int j = wmax;j >= 0;j--)
    			{
    				int temp = first[i]; //这是邻接表读取数据的方法 
    				while (temp != 0)
    					{
    						int l = what[temp];
    						if (j >= w[l]) //如果没有超过背包容量 则进行更新 
    							{
    								if (f[j] < f[j-w[l]] + c[l])
    									f[j] = f[j-w[l]] + c[l];
    							}
    						temp = next[temp];
    					}
    			}	
    	printf("%d",f[wmax]); //最后输出答案。 
    	return 0;	
    }


  • 相关阅读:
    ASP记录(一)
    ASP HTML JS CSS JQ之间恩怨
    ASP记录(二)之Input
    网页范例
    初识GoAhead
    TCP、IP、Http、Socket、telnet
    自定义博客的背景图片
    工具管理操作类介绍
    STL string的构造函数
    cout 格式化输出
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7632370.html
Copyright © 2011-2022 走看看