首页 > 其他分享 >POJ 1636 Prison rearrangement 二部图连通分量+背包

POJ 1636 Prison rearrangement 二部图连通分量+背包

时间:2023-02-21 19:03:22浏览次数:31  
标签:监狱 p2 p1 1636 int POJ pcnt Prison dp


以第三组为例,我们根据输入可以得到这个二部图

POJ 1636 Prison rearrangement 二部图连通分量+背包_二部图

根据不能放在一起的情况可以得到这样的连通分量
对于每一个连通分量,我们将这个连通分量按照监狱分为两个部分
这两个部分调整的时候要作为整体来调整。
**Eg:**我们假设将一号监狱的5调到二号监狱,则二号监狱的5要到一号监狱,随之一号监狱的2,3,4也要调到二号监狱。

所以
我们找到所有的连通分量,按照监狱各自分为两个部分,视为两个物品
②运用背包模型,对物品进行调整
转态转移

dp[j][k]表示,存在方案使得第一个监狱出j个人,第二个监狱出k个人的调整,j k不一定相等

对于第i个连通分量,第一个监狱对应p1[i]个人,第二个监狱对应p2[i]个人

if( dp[ j-p1[i] ] [ k-p2[i] ] == 1 ){
dp[j][k] = 1;
}

则有如上关系。
注意由于每一个物品只能使用一次,并且是恰好填满的情况,
所有遍历顺序是从下至上,从右至左

③遍历dp数组,取得dp[i][i]==1的时候,最大的i值即为答案。
表示一号监狱与二号监狱拿出的人数一样多,切有这样的方案。

#include <iostream>
#include <stdio.h>
#include <string>
#include <string.h>
#include <vector>
#include <cstdio>

using namespace std;

#define debug(x) cout<<#x<<": "<<x<<endl;

int n,m,r;

int p1[201];
int p2[201];
vector<int> danp[401];

bool visit[402];

bool dp[101][101];

int pcnt = 0;
int xi=0;
int yi=0;

void dfs(int a){
//debug(n)
visit[a] = 1;
if( a<=m ){
p1[pcnt] ++;
}else{
p2[pcnt] ++;
}
vector<int>&v = danp[a];
for(int i=0;i < v.size();i++){
if( visit[ v[i] ] == 0 ){
dfs(v[i]);
}
}
}

int main()
{
scanf("%d",&n);
for(int nn = 0;nn < n; nn ++){
scanf("%d%d",&m,&r);

for(int i=0;i<= m*2;i++){
danp[i].clear();
}

memset(visit,0,sizeof(visit));
memset(p1,0,sizeof(p1));
memset(p2,0,sizeof(p2));
memset(dp,0,sizeof(dp));



pcnt = 0;
//debug(000)

for(int rr=0;rr<r;rr++){

scanf("%d%d",&xi,&yi);
danp[xi].push_back(m+yi);
danp[m+yi].push_back(xi);
}

//debug(111)

for(int i=1;i <= 2*m;i ++){
if( visit[i] == 0 ){
dfs(i);
pcnt++;

}
}

int ret = 0;
dp[0][0] = 1;
for(int i = 0;i < pcnt;i++){
for(int j = m/2;j >=p1[i] ;j--){
for(int k = m/2;k >= p2[i];k--){
if( dp[ j-p1[i] ] [ k-p2[i] ] == 1 ){
dp[j][k] = 1;
}
}
}
}
for(int i = m/2;i >=0;i--){
if( dp[i][i] == 1 ){
ret = i;
break;
}
}

cout<<ret<<endl;
}
return 0;
}

POJ 1636 Prison rearrangement 二部图连通分量+背包_连通分量_02


标签:监狱,p2,p1,1636,int,POJ,pcnt,Prison,dp
From: https://blog.51cto.com/liyunhao/6077026

相关文章

  • POJ 2228 Naptime 环形DP
    先不考虑环的情况dp[i][j][0]:前i个时间间隔中,已经花费了j个间隔,取得的最大值,并且第i个间隔在休息dp[i][j][1]:前i个时间间隔中,已经花费了j个间隔,取得的最大值,并且第i个间......
  • [SPOJ] DIVCNT2 - Counting Divisors (square) (平方的约数个数前缀和 容斥 卡常)
    题目vjudgeURL:​​CountingDivisors(square)​​​Letbethenumberofpositivedivisorsof.Forexample,,and.LetGiven,find.InputFirstlinecontains......
  • POJ 3345 Bribing FIPA
      #include<iostream>#include<map>#include<algorithm>#include<cstring>usingnamespacestd;constintN=203,M=N;typedeflonglongll;intn......
  • poj 2230
    求一个无向图的欧拉回路,但要求每条边正反过一次 当作有向图,打标记只打一条边 #include<iostream>#include<algorithm>#include<cstring>#include<stack>usi......
  • POJ - 1664 放苹果
    把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1是同一种分法。Input第一行是测试数据的数目t(0<=t<=20)。以下每行均包......
  • 二分查找水题--疯牛(POJ 2456)
    DescriptionFarmerJohnhasbuiltanewlongbarn,withN(2<=N<=100,000)stalls.Thestallsarelocatedalongastraightlineatpositionsx1,...,xN(0<=x......
  • Poj 2503 map sscanf
    Poj2503mapsscanf题意字符串的映射,但它输入的方式很怪。首先每行输入两个单词,中间隔一个空格,到输入空行为止。然后每行输入一个单词,如果能存在映射的单词就输出对......
  • Pseudoprime numbers(POJ-3641 快速幂)
    快速幂:快速幂就是所求的幂次方过大,导致代码所用的时间超限。如:求2^3,3的二进制是11,(n&1)判断次方数的二进制是否为1,n>>1,向右进位1:代码:k=1,t=n;while(n){if(n&1)//......
  • Cash Machine (POJ 1276)(多重背包——二进制优化)
    链接:POJ-1276题意:给你一个最大金额m,现在有n种类型的纸票,这些纸票的个数各不相同,问能够用这些纸票再不超过m的前提下凑成最大的金额是多少?题解:写了01背包直接暴力,结......
  • Subsequence (POJ - 3061)(尺取思想)
    ProblemAsequenceofNpositiveintegers(10<N<100000),eachofthemlessthanorequal10000,andapositiveintegerS(S<100000000)aregiven.W......