poj 1636 Prison rearrangement

52 篇文章 0 订阅
16 篇文章 0 订阅
Prison rearrangement
Time Limit: 3000MS Memory Limit: 10000K
Total Submissions: 1995 Accepted: 900

Description

In order to lower the risk of riots and escape attempts, the boards of two nearby prisons of equal prisoner capacity, have decided to rearrange their prisoners among themselves. They want to exchange half of the prisoners of one prison, for half of the prisoners of the other. However, from the archived information of the prisoners' crime history, they know that some pairs of prisoners are dangerous to keep in the same prison, and that is why they are separated today, i.e. for every such pair of prisoners, one prisoners serves time in the first prison, and the other in the second one. The boards agree on the importance of keeping these pairs split between the prisons, which makes their rearrangement task a bit tricky. In fact, they soon find out that sometimes it is impossible to fulfil their wish of swapping half of the prisoners. Whenever this is the case, they have to settle for exchanging as close to one half of the prisoners as possible.

Input

On the first line of the input is a single positive integer n, telling the number of test scenarios to follow. Each scenario begins with a line containing two non-negative integers m and r, 1 < m < 200 being the number of prisoners in each of the two prisons, and r the number of dangerous pairs among the prisoners. Then follow r lines each containing a pair xi yi of integers in the range 1 to m,which means that prisoner xi of the first prison must not be placed in the same prison as prisoner yi of the second prison.

Output

For each test scenario, output one line containing the largest integer k <= m/2 , such that it is possible to exchange k prisoners of the first prison for k prisoners of the second prison without getting two prisoners of any dangerous pair in the same prison.

Sample Input

3
101 0
3 3
1 2
1 3
1 1
8 12
1 1
1 2
1 3
1 4
2 5
3 5
4 5
5 5
6 6
7 6
8 7
8 8

Sample Output

50
0
3
 
题意:有两个总囚犯数相同,都为m的监狱,计划将这两个监狱不超过m/2的囚犯对调,但是监狱A的若干囚犯和监狱B的若干囚犯不能放在一起,在满足这些囚犯不能放在一起的条件下,要使得对调的囚犯数达到最多。
思路:以第三个样例为例子:

如下图,左边的代表监狱A,右边的代表监狱B。现在问题就变成这样了:两个监狱要以组为单位进行交换。因为最多交换一半,所以选第3、4组进行交换,最后每个监狱的交换人数为3。

从另一个角度,分组后的选择问题,有点像二维背包。每一组有两个值,从A里选的人数和从B里选的人数。即,每组相当于一个物品,有重量和体积。限制条件也有两个:从A中选择的总人数和从B中选择的总人数不能超过监狱容量的一半。即,背包的重量和体积都有限。最终要使交换的人尽可能的多。即,背包装得东西尽可能多。 

这里的分组用DFS解决

AC代码:

#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cmath>
#include <vector>
#include <cstdlib>

using namespace std;
bool vis[2][205];     //vis[0][i]表示监狱A的i是否被访问过,vis[1][i]表示监狱B的i是否被访问过
bool map[205][205];   //map[i][j]表示监狱A的i和监狱B的j是否发生冲突
int asize;  //监狱A要交换的人数
int bsize; //监狱B要交换的人数
bool dp[205][205];
int m,r;
void init()
{
    memset(map,0,sizeof(map));
    memset(dp,0,sizeof(dp));
    memset(vis,0,sizeof(vis));
}
void Input()
{
    cin>>m>>r;
    int a,b;
    while(r--)
    {
        cin>>a>>b;
        map[a][b]=1;
    }
}
void DFS(int part,int id)  //part代表搜索到的分组,id代表搜索到编号
{
    vis[part][id]=1;
    if(part==0)
    {
        asize++;
        for(int i=1;i<=m;i++)
        if(map[id][i]&&!vis[1][i])
        DFS(1,i);
    }
    else
    {
        bsize++;
        for(int i=1;i<=m;i++)
        if(map[i][id]&&!vis[0][i])
        DFS(0,i);
    }
}
void bag()
{
    dp[0][0]=true;
    for(int i=m/2;i>=asize;i--)  
    for(int j=m/2;j>=bsize;j--)  
    if(dp[i][j]||dp[i-asize][j-bsize]) dp[i][j]=true;
}
void Ouput()
{
    for(int i=m/2;i>=0;i--)
    if(dp[i][i])
    {
        cout<<i<<endl;
        break;
    }
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        init();
        Input();
        for(int i=1;i<=m;i++)
        if(!vis[0][i])
        {
            asize=0;
            bsize=0;
            DFS(0,i);
            bag();
        }
        for(int i=1;i<=m;i++)
        if(!vis[1][i])
        {
            asize=0;
            bsize=0;
            DFS(1,i);
            bag();
        }
        Ouput();
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值