#include<set>
#include<queue>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<vector>
using namespace std;
const int INF = 0xFFFFFFF;
const int maxn = 51;
int n,m,k;
struct Node{
int x,y;
Node(){ x=y=0;}
Node(int _x,int _y){ x=_x,y=_y;}
};
set<int>p[26];
Node person[51],post[26];
double d[26];
bool canUse[26];
void test(){
for(int i=0;i<m;i++)
if(canUse[i])
{
printf("邮局%d的村民有 :",i+1);
for(set<int>::iterator it=p[i].begin();it!=p[i].end();it++) printf("%d ",*it+1);
printf("\n总距离%lf\n",d[i]);
}
}
double dis(int index1,int index2)
{
Node house = person[index1];
Node po = post[index2];
int x1=house.x,y1=house.y;
int x2=po.x,y2=po.y;
double sum = (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1);
return sqrt(sum);
}
int findMinPost(int index) //找到最近的邮局的编号(可用的邮局)
{
Node temp=person[index];//找到这个人的最近可用邮局
double MIN = INF;
int u = -1;
for(int i=0;i<m;i++)
{
if(canUse[i])
{
if(dis(index,i)<MIN)
{
u=i;
MIN=dis(index,i);
}
}
}
return u;
}
int main(void)
{
int x,y;
cin>>n>>m>>k;
for(int i=0;i<n;i++)
{
cin>>x>>y;
person[i].x=x,person[i].y=y;
}
for(int i=0;i<m;i++)
{
cin>>x>>y;
canUse[i]=true;
post[i].x=x,post[i].y=y;
}
for(int i=0;i<n;i++)
{
int pos=findMinPost(i);
p[pos].insert(i);
}
for(int i=0;i<m;i++)
{
d[i]=0;
for(set<int>::iterator it=p[i].begin();it!=p[i].end();it++)
{
d[i]+=dis(*it,i);
}
}
//test
test();
for(int i=0;i<m-k;i++)//删除m-k个邮局
{
printf("第%d次删除\n",i+1);
int u=-1,MIN=INF;
for(int j=0;j<m;j++)
if(canUse[i])
{
if(p[j].size()<MIN)
{
u=j,MIN=p[j].size();
}
else if(p[j].size()==MIN)
{
if(d[j]>d[u])
{
u=j;
MIN=p[j].size();
}
}
}
canUse[u]=false;
for(set<int>::iterator it=p[u].begin(); it != p[u].end();it++)
{
int pos=findMinPost(*it);
p[pos].insert(*it);
d[pos]+=dis(*it,pos);
}
test();
printf("\n\n");
}
for(int i=0;i<m;i++)
if(canUse[i]) printf("%d ",i+1);
return 0;
}
</pre>AC思路(dfs+剪枝):dfs最重要的就是建立搜索树,这里每个点都有两种状态,如果直接暴力时间肯定很长,所以需要加上剪枝,我们可以将村子的住户还有备用邮局看作是两个集合,就像普利姆的思路一样,总的思路就是更新最短距离数组,我们先将所有的点全部连接在第一个备用邮局,也可以不连第一个,毕竟每个点有两种状态,如果第二个备用邮局到住户的距离足以更新最短距离数组,那就更新之后寻找下一个邮局,如果不足以更新最短距离数组,我们就直接放弃这个点,显然他是没有用的,找到k个邮局之后就判定一下话费,是否更短,如果是,更新序号数组
[cpp] view plaincopyprint?
#include<iostream>
#include<stdlib.h>
#include<math.h>
using namespace std;
int n,m,k,j,c[55][2],y[27][2],d[12],f1,f2,f[55]={0};
float yc[27][55],s=1000000000;
int dfs(int t,int i,int o[12],float w[55],float sum)
{
if(i<=m+1)
{
if(t==k)
{
if(sum<s)
{
s=sum;
for(j=0;j<k;j++)
d[j]=o[j];
}
}
else if(i<=m&&t<k)
{
float ww[55];
for(j=1;j<=n;j++)
ww[j]=w[j];
dfs(t,i+1,o,w,sum);
f1=1,f2=0;
if(!f[i])
{
o[t]=i;
if(t>0)
{
f2=1;
for(j=1;j<=n;j++)
{
if(ww[j]>yc[i][j])
{
sum=sum-ww[j]+yc[i][j];
ww[j]=yc[i][j];
f1=0;
}
}
}
else
{
for(j=1;j<=n;j++)
{
sum+=yc[i][j];
ww[j]=w[j]=yc[i][j];
}
}
if(f1&&f2)
{
f[i]=1;
dfs(t,i+1,o,w,sum);
}
else
dfs(t+1,i+1,o,ww,sum);
}
}
}
}
int main()
{
int i,j,o[12];
float w[55],ww[55];
cin>>n>>m>>k;
for(i=1;i<=n;i++)
cin>>c[i][0]>>c[i][1];
for(i=1;i<=m;i++)
{
cin>>y[i][0]>>y[i][1];
for(j=1;j<=n;j++)
yc[i][j]=sqrt((c[j][0]-y[i][0])*(c[j][0]-y[i][0])+(c[j][1]-y[i][1])*(c[j][1]-y[i][1]));
}
dfs(0,1,o,w,0);
for(i=0;i<k;i++)
cout<<d[i]<<" ";
return 0;
}
/*
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
int a[]={1,2,3,4,5,6};
sort(a,a+6);
do
{
for(int i=0;i<6;i++)
cout<<a[i];
cout<<endl;
}while(next_permutation(a,a+6));
return 0;
}
*/
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
int a[]={1,2,3,4,5,6};
sort(a,a+6);
reverse(a,a+6);
do
{
for(int i=0;i<6;i++)
cout<<a[i];
cout<<endl;
}while(prev_permutation(a,a+6));
return 0;
}