原始部落中的居民们为了争夺有限的资源,经常发生冲突。几乎每个居民都有他的仇敌。部落酋长为了组织一支保卫部落的队伍,希望从部落的居民中选出最多的居民入伍,并保证队伍中任何2个人都不是仇敌。给定仇敌关系,编写最佳方案。
输入:第一行有2个正整数n和c,表示部落中有n个居民,居民间有c个仇敌关系。
接下来的c行中,每行有2个正整数e1和e2,表示居民e1与居民e2是仇敌
输出:第1行是部落卫队的总人数bestn;第2行是卫队组成xi,1≤i≤n,xi=0表示居民i不在卫队中,xi=1表示居民i在卫队中。
代码:
#include<bits/stdc++.h>
using namespace std;
#define M 100
int n,c; //n:居民数 c:仇敌数
int a[M][M]; //存储仇敌关系,a[i][j]=1表示两人之间有仇敌关系
int x[M]; //居民是否被选入进入部落卫队,1表示进入,0表示未进入
int cp=0; //当前部落卫队人数
int bestn=0; //当前最大部落卫队人数
int bestx[M]; //当前最优解,即哪些居民组成部落卫队
//数据输入
void Inputdata()
{
int i,e1,e2;
cout<<"请输入居民数:";
cin>>n;
cout<<endl;
cout<<"请输入仇敌关系数:";
cin>>c;
cout<<endl;
cout<<"请依次输出仇敌关系(e1,e2):";
cout<<endl;
for(i=1;i<=c;i++)
{
cin>>e1>>e2;
a[e1][e2]=1;
a[e2][e1]=1;
}//for
}//Inputdata
void Output()
{
int i;
cout<<"部落卫队总人数:";
cout<<bestn<<endl;
cout<<"部落卫队组成:";
for(i=1;i<=n;i++)
cout<<bestx[i]<<" ";
cout<<endl;
}//Output
//回溯
void Backtrack(int i)
{
int j;
if(i > n) //到达叶结点
{
for(j=1;j<=n;j++)
{
bestx[j]=x[j];
}//for
bestn=cp;
return ;
}//if
bool flag=true; //设置友好标志,初始设置入选卫队的成员无敌对关系
for(j=1;j<i;j++)
{
if(x[j]==1 && a[i][j]==1) //如果i与前i-1个且已加入卫队的成员j存在敌对关系
{
flag=false; //不必考虑左子树,设置敌对关系
break;
}//if
}//for
if(flag) //满足约束条件,进入左子树
{
x[i]=1; //记录当前第i个成员进入
cp++; //当前结点数加1
Backtrack(i+1); //继续搜索下一层
x[i]=0;
cp--;
}//if
if(cp+n-i>bestn) //仅当可能有最优值才执行,即满足限界条件进行剪枝,进入右子树
{
x[i]=0; //记录第i个成员没有进入
Backtrack(i+1); //继续搜索下一层
}//if
}//Backtrack
int main()
{
Inputdata();
Backtrack(1);
Output();
return 0;
}
截图: