Prison Rearrangement
Submitted : 62, Accepted : 36
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 fulfill 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个囚犯,现在希望交换一些人,尽可能从监狱1中拿出m/2个人与监狱2中的m/2个人交换监狱。有部分囚犯不能在同一个监狱,求做多能交换多少个人(最大为m/2)
思路:我们把一个囚犯换到另一个监狱,那么与他冲突的囚犯就会来到他先前的监狱,那些冲突的囚犯来到先前的监狱之后又会有冲突的囚犯,新的冲突的囚犯就又要到另一个监狱了,所以我们换一个人的时候,相当于从监狱1拿出来了x个人,监狱2拿出了y个人,换了一下位置,只有专业那个才不会冲突。那么我们把整个会互相影响的看成一个整体,就是一换就将这里面的所有人一起换。那么我们用dp[i][j][k]=true 表示对前i个物品,监狱1能达到i个人,监狱2能达到j个人。
代码:
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<vector>
#include<map>
using namespace std;
#define mp make_pair
#define max(a,b) (a) < (b) ? (b) : (a)
#define LL long long
#define eps 1e-8
const int maxn = 210;
struct Item
{
int c1 , c2;
}item[maxn*2];
bool vis[2][maxn];
vector<int> G[2][maxn];
bool dp[maxn][maxn];
int sz , m , r;
int rest1 , rest2;
void dfs(int now,int x)
{
if (vis[now][x]) return;
vis[now][x] = true;
if (now) ++item[sz].c2 , --rest2;
else ++item[sz].c1 , --rest1;
for (int i = 0 ; i < G[now][x].size() ; ++i)
{
int y = G[now][x][i];
if (vis[!now][y]) continue;
dfs(!now,y);
}
}
void init()
{
for (int i = 0 ; i <= m ; ++i) G[0][i].clear() , G[1][i].clear() , vis[0][i] = vis[1][i] = true;
memset(item,0,sizeof(item));
sz = 1 , rest1 = rest2 = m;
}
void input()
{
while (r--)
{
int x , y;
scanf("%d%d",&x,&y);
G[0][x].push_back(y);
G[1][y].push_back(x);
vis[0][x] = false;
vis[1][y] = false;
}
}
void solve()
{
memset(dp,0,sizeof(dp));
for (int i = 1 ; i <= m ; ++i) if (!vis[0][i])
{
dfs(0,i);
++sz;
}
for (int i = 1 ; i <= m ; ++i) if (!vis[1][i])
{
dfs(1,i);
++sz;
}
for (int i = 0 ; i <= rest1 ; ++i)
for (int j = 0 ; j <= rest2 ; ++j)
dp[i][j] = true;
for (int i = 1 ; i < sz ; ++i)
{
for (int j = m ; j >= item[i].c1 ; --j)
{
for (int k = m ; k >= item[i].c2 ; --k) if (!dp[j][k])
{
int c1 = item[i].c1 , c2 = item[i].c2;
if (dp[j-c1][k-c2]) dp[j][k] = true;
}
}
}
int ans;
for (ans = m/2 ; ans >= 0 ; --ans) if (dp[ans][ans])
{
printf("%d\n",ans);
return;
}
}
int main()
{
int T;
cin>>T;
while (T--)
{
scanf("%d%d",&m,&r);
init();
input();
solve();
}
}
题后语:整体的思想是多那么重要,这里面如果一个一个囚犯来想,那就是剪不断,理还乱。从这里面看出了牵一发而动全身的威力,一个人能影响一群人,因为你,可能别人的人不能呆在自己的地方,不得不到别的地方,又有人因为这些不得不到别的地方的人又不得不到别的地方,又有人因为。。。。人口迁移是这样来的吗?