题意:有N = 3*K个城市,每个城市有1000头牛,每个城市的牛支持A或B,请将这N个城市分为3个地区,每个地区含有K个城市,且要使至少两个地区A的支持率高。
题解:首先将输入进行处理,保存每个城市支持数的差值,然后进行排序,因为一定有解,所以在前2*K个城市当中一定可以找到两个都满足要求的划分,则剩余K个城市直接划分为一个地区。
典型的组合数DFS,为了达到从2*N个牛中选择K个牛组成一个地区,可以按照地区中的城市号递增地选择城市。
剪枝:
- 剩下的城市数已经不能组成一个地区。
- 设sum[i]为从第i个到第2*K个城市的总差值,已经达到的差值为sumDiff,因为已经城市支持率为逆序,则剩下的城市要划分到地区1能获得最大的差值只能从beginCity一直连续取K-cliqueSize个城市,即若sumDiff+sum[beginCity]-sum[K-cliqueSize+beginCity] <= 0则地区1肯定不能满足要求。
- 类似的,剩下的城市要划分到地区0能获得的最大差值就是把从N逆序连续取K-cliqueSize个的城市全部给地区1,即sum[1]-(sumDiff+sum[N-K+cliqueSize+1]) <= 0则地区0肯定不能满足要求。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node
{
int num;
int index;
bool friend operator<(const node& a,const node& b)
{
return a.num > b.num;
}
};
class solve
{
private:
int K;
int N;
node* diffNum;
int* sumDiffNum; //从第i个到N的总差值
char* clique;
public:
solve(int k):K(k),N(3*k)
{
diffNum = new node[N+1];
sumDiffNum = new int[N+2];
clique = new char[N+1];
memset(clique,0,sizeof(char)*(N+1));
memset(sumDiffNum,0,sizeof(int)*(N+2));
processIn();
DFS(0,1,0);
printClique(0);
}
~solve()
{
delete[] diffNum;
delete[] clique;
delete[] sumDiffNum;
}
int processIn();
int DFS(char cliqueSize,char beginCity,int sumDiff);
int printClique(char cliqueFlag);
};
int solve::printClique(char cliqueFlag)
{
if(cliqueFlag == 2)
return 0;
for(int i = 1;i <= N;i++)
{
if(clique[i] == cliqueFlag)
{
printf("%d\n",diffNum[i].index);
}
}
printClique(cliqueFlag+1);
return 0;
}
int solve::DFS(char cliqueSize,char beginCity,int sumDiff)
{
if(cliqueSize == K)
{
if(sumDiff <= 0||sumDiffNum[1]-sumDiff <= 0)
return 0;
return 1;
}
if(cliqueSize+N-beginCity+1 < K||
//剩下的城市数已不足以形成区
sumDiff+sumDiffNum[beginCity]-sumDiffNum[K-cliqueSize+beginCity] <= 0||
//剩下的地区1最大划分不满足要求
sumDiffNum[1]-(sumDiff+sumDiffNum[N-K+cliqueSize+1]) <= 0)
//剩下的地区0最大划分不满足要求
return 0;
for(int i = beginCity;i <= N;i++)
{
clique[i] = 1;
if(DFS(cliqueSize+1,i+1,sumDiff+diffNum[i].num))
return 1;
clique[i] = 0;
}
return 0;
}
int solve::processIn()
{
int tmpNum;
for(int i = 1;i <= N;i++)
{
scanf("%d",&tmpNum);
diffNum[i].num = 2*tmpNum-1000;
diffNum[i].index = i;
}
sort(diffNum+1,diffNum+N+1);
for(int i = 2*K+1;i <= N;i++)
//直接输出的最小的K个城市
{
printf("%d\n",diffNum[i].index);
}
N -= K;
for(int i = N;i >= 1;i--)
{
sumDiffNum[i] += sumDiffNum[i+1]+diffNum[i].num;
}
return 0;
}
int main()
{
int k;
while(~scanf("%d",&k))
{
solve poj_2454(k);
}
return 0;
}