您的位置:首页 > 理论基础

2012年湖南省第八届大学生计算机程序设计竞赛 F 题 Kingdoms

2014-05-11 13:21 316 查看
题目大意:

给你n个城市,m条道路,每个城市有P【i】个人,每条道路都有一个COST,要求总COST不超过K的情况下,使得连接城市的人口最多且必须包括第一个城市

因为N最大为16且第一个城市必被选择,所以只需枚举剩下N-1个城市的状态即可,枚举每个状态的时候,求出目前的最小生成树的COST,若COST小于K,则更新ans

这题我知道怎么写之后一直没写对,今天终于找出错误了,感觉自己太傻吊了。。。

错误: 在求最小生成树时,我用hash【】去记录那些点已被加入到最小生成树中, 然后根据hash算出当前状态的总人口,这样就会在城市1没有加入到最小生成树的时候,

ans也更新了

AC代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>

using namespace std;

struct node
{
int x,y,c;
}edge[202],a[202];

int n, m, k;
int Father[20];
int p[20];
int vis[20]; // 标记改点是否选择
//int hash[20];

int cmp(node x, node y)
{
return x.c< y.c;
}

int find(int x)
{
return x == Father[x]?  x : Father[x]= find(Father[x]);
}

int dij(int nn,int mm)
{
//memset(hash, 0, sizeof(hash));
for(int i= 0; i< n; i++)
Father[i]= i;
sort(a+1, a+mm+1, cmp);
int ans= 0;
int bian= 1, dian= 1;
while(dian<= nn-1 &&bian<= mm)
{
int vf1= find(a[bian].x);
int vf2= find(a[bian].y);

if(vf1!= vf2)
{
//hash[a[bian].x]= 1;
//	hash[a[bian].y]= 1;
dian++;
ans+= a[bian].c;
Father[vf2]= vf1;
}
bian++;
}
if(dian == nn)
return ans;
else
return 10000000;
}

int main()
{
int t; scanf("%d",&t);
while(t--)
{
scanf("%d %d %d",&n,&m,&k);
for(int i= 1; i<= n; i++)
scanf("%d",&p[i-1]);
for(int i= 1; i<= m; i++)
{
int a,b, num;
scanf("%d %d %d",&a,&b,&num);
edge[i]= (node){a-1, b-1, num};
}
int ans= 0;
for(int S= 0; S< (1<<(n-1)); S++) //第一点必选,枚举剩下的n-1个点的状态
{
int sumn= 1;
int summ= 0;
memset(vis, 0, sizeof(vis));
vis[0]= 1;
for(int i= 0; i< n-1; i++)
if(S & (1<< i)) //若选择第i+1个城市, 城市的标号为0-(N-1)
{
vis[i+1]= 1;
sumn++;
}
for(int i= 1; i<= m; i++)
if(vis[edge[i].x] && vis[edge[i].y])
{
summ++;
a[summ]= (node){edge[i].x, edge[i].y, edge[i].c};
}
int cost= dij(sumn, summ);
int xixi= p[0];
if(cost<= k)
{
for(int i= 1; i< n; i++)
if(vis[i]) //之前这里用hash标记然后判断hash[i],最后发现当最小生成树中不包括点0时也会更新ans
xixi+= p[i];
if(xixi> ans)
ans= xixi;
}
}
printf("%d\n",ans);
}
return 0;
}


之前WA的代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>

using namespace std;

struct node
{
int x,y,c;
}edge[202],a[202];

int n, m, k;
int Father[20];
int p[20];
int vis[20]; // 标记改点是否选择
int hash[20];

int cmp(node x, node y)
{
return x.c< y.c;
}

int find(int x)
{
return x == Father[x]?  x : Father[x]= find(Father[x]);
}

int dij(int nn,int mm)
{
memset(hash, 0, sizeof(hash));
for(int i= 0; i< n; i++)
Father[i]= i;
sort(a+1, a+mm+1, cmp);
int ans= 0;
int bian= 1, dian= 1;
while(dian<= nn-1 &&bian<= mm)
{
int vf1= find(a[bian].x);
int vf2= find(a[bian].y);

if(vf1!= vf2)
{
hash[a[bian].x]= 1;
hash[a[bian].y]= 1;
dian++;
ans+= a[bian].c;
Father[vf2]= vf1;
}
bian++;
}
return ans;
}

int main()
{
int t; scanf("%d",&t);
while(t--)
{
scanf("%d %d %d",&n,&m,&k);
for(int i= 1; i<= n; i++)
scanf("%d",&p[i-1]);
for(int i= 1; i<= m; i++)
{
int a,b, num;
scanf("%d %d %d",&a,&b,&num);
edge[i]= (node){a-1, b-1, num};
}
int ans= 0;
for(int S= 0; S< (1<<(n-1)); S++) //第一点必选,枚举剩下的n-1个点的状态
{
int sumn= 1;
int summ= 0;
memset(vis, 0, sizeof(vis));
vis[0]= 1;
for(int i= 0; i< n-1; i++)
if(S & (1<< i)) //若选择第i+1个点
{
vis[i+1]= 1;
sumn++;
}
for(int i= 1; i<= m; i++)
{

if(vis[edge[i].x] && vis[edge[i].y])
{
summ++;
a[summ]= (node){edge[i].x, edge[i].y, edge[i].c};
}
}
int cost= dij(sumn, summ);
int xixi= p[0];
if(cost<= k)
{
for(int i= 1; i< n; i++)
if(hash[i])
{
xixi+= p[i];
}
if(xixi> ans)
ans= xixi;
}
}
printf("%d\n",ans);
}
return 0;
}


测试数据

3

4 1 3

100 200 300 400

3 4 1

输出

800

原因就是枚举状态110的时候, ans也更新了。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: