您的位置:首页 > 其它

畅通工程,继续畅通工程,畅通工程再续,多种解法

2015-08-11 15:05 387 查看

继续畅通工程

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 17822 Accepted Submission(s): 7672


[align=left]Problem Description[/align]

省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。现得到城镇道路统计表,表中列出了任意两城镇间修建道路的费用,以及该道路是否已经修通的状态。现请你编写程序,计算出全省畅通需要的最低成本。

[align=left]Input[/align]

测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( 1< N < 100 );随后的 N(N-1)/2 行对应村庄间道路的成本及修建状态,每行给4个正整数,分别是两个村庄的编号(从1编号到N),此两村庄间道路的成本,以及修建状态:1表示已建,0表示未建。

当N为0时输入结束。

[align=left]Output[/align]

每个测试用例的输出占一行,输出全省畅通需要的最低成本。

[align=left]Sample Input[/align]

3 1 2 1 0 1 3 2 0 2 3 4 0 3 1 2 1 0 1 3 2 0 2 3 4 1 3 1 2 1 0 1 3 2 1 2 3 4 1 0

[align=left]Sample Output[/align]

3 1 0

题解:

方法一:克鲁斯卡尔算法;

代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
const int MAXN=110;
int sum;
struct Node {
int s,e,d,ol;
};
Node dt[MAXN*MAXN/2];
int pre[MAXN];
void initial(){
memset(pre,0,sizeof(pre));
memset(dt,0,sizeof(dt));
}
int find(int x){
return pre[x]= x==pre[x]?x:find(pre[x]);
}
int cmp(const void *a,const void *b){
if( (*(Node *)a).ol != (*(Node *)b).ol)return (*(Node *)b).ol-(*(Node *)a).ol;
else return (*(Node *)a).d-(*(Node *)b).d;
}
void merge(Node a){
int f1,f2;
if(!pre[a.s])pre[a.s]=a.s;
if(!pre[a.e])pre[a.e]=a.e;
f1=find(a.s);
f2=find(a.e);
if(f1!=f2){
pre[f1]=f2;
if(!a.ol)sum+=a.d;
}
}
int main(){
int N,t;
while(~scanf("%d",&N),N){
initial();sum=0;
t= N*(N-1)/2;
int i,j;
for(i=0;i<t;i++)
scanf("%d%d%d%d",&dt[i].s,&dt[i].e,&dt[i].d,&dt[i].ol);
qsort(dt,t,sizeof(dt[0]),cmp);
for(int i=0;i<t;i++){
merge(dt[i]);
}
printf("%d\n",sum);
}
return 0;
}


方法二:prime:

代码:

#include<stdio.h>
#include<string.h>
const int INF=0x3f3f3f3f;
const int MAXN=110;
int vis[MAXN],map[MAXN][MAXN],low[MAXN];
int N;
void prime(){
memset(vis,0,sizeof(vis));
for(int i=1;i<=N;i++)low[i]=map[1][i];
vis[1]=1;
int k,temp,min=0;
for(int i=1;i<=N;i++){
temp=INF;
for(int j=1;j<=N;j++)
if(!vis[j]&&temp>low[j])temp=low[k=j];

if(temp==INF){
printf("%d\n",min);
break;
}
min+=temp;
vis[k]=1;
for(int j=1;j<=N;j++){
if(!vis[j]&&low[j]>map[k][j])low[j]=map[k][j];
}
}
}
int main(){int a,b,c,d,M;
while(~scanf("%d",&N),N){
M=N*(N-1)/2;
memset(map,INF,sizeof(map));
//printf("%d %d\n",M,N);
// for(int i=0;i<10;i++)for(int j=0;j<10;j++)printf("%d ",map[i][j]);
while(M--){
scanf("%d%d%d%d",&a,&b,&c,&d);
if(d)map[a]=map[b][a]=0;
else if(c<map[a][b])map[a][b]=map[b][a]=c;
}
prime();
}
return 0;
}


[align=center][b]欢迎参加——每周六晚的BestCoder(有米!)
[/align]

畅通工程

Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 21373 Accepted Submission(s): 9196


[align=left]Problem Description[/align]
省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。经过调查评估,得到的统计表中列出了有可能建设公路的若干条道路的成本。现请你编写程序,计算出全省畅通需要的最低成本。

[align=left]Input[/align]
测试输入包含若干测试用例。每个测试用例的第1行给出评估的道路条数 N、村庄数目M ( < 100 );随后的 N
行对应村庄间道路的成本,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间道路的成本(也是正整数)。为简单起见,村庄从1到M编号。当N为0时,全部输入结束,相应的结果不要输出。

[align=left]Output[/align]
对每个测试用例,在1行里输出全省畅通需要的最低成本。若统计数据不足以保证畅通,则输出“?”。

[align=left]Sample Input[/align]

3 3 1 2 1 1 3 2 2 3 4 1 3 2 3 2 0 100

[align=left]Sample Output[/align]

3 ?

题解:

方法一:克鲁斯卡尔算法;

代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct Node {
int s,e,dis;
};
Node road[110];
int pre[110];
int N,M;
int cmp(const void *a,const void *b){
return *(int *)a-*(int *)b;
}
int find(int x){
return x==pre[x]?x:find(pre[x]);
}
bool merge(int x,int y){
int f1,f2;
f1=find(x);f2=find(y);
if(f1!=f2){
pre[f1]=f2;return true;
}
return false;
}
void initial(){memset(pre,0,sizeof(pre));}
int main(){
while(~scanf("%d%d",&N,&M),N){
for(int i=0;i<N;i++)scanf("%d%d%d",&road[i].s,&road[i].e,&road[i].dis);
qsort(road,N,sizeof(road[0]),cmp);
int num=0;
initial();
for(int i=0;i<N;i++){
if(!pre[road[i].s])pre[road[i].s]=road[i].s;
if(!pre[road[i].e])pre[road[i].e]=road[i].e;
if(merge(road[i].s,road[i].e))num+=road[i].dis;
}int flot=0;
for(int i=1;i<=M;i++){
if(!pre[i]||i==pre[i])flot++;
if(flot>1)break;
}
if(flot>1)puts("?");
else printf("%d\n",num);
}
return 0;}


方法二:prime算法:

#include<stdio.h>
#include<string.h>
const int INF=0x3f3f3f3f;
const int MAXN=110;
int map[MAXN][MAXN],vis[MAXN],low[MAXN];
int N,M,min;
void prime(){
memset(vis,0,sizeof(vis));//记得初始化
int flot=1,k;
for(int i=1;i<=M;i++)
low[i]=map[1][i];//初始化low数组,刚开始已选集合{1}与此集合相连的权值为集合low
vis[1]=1;//1在集合中visit【1】=1;
for(int i=1;i<=M;i++){
int temp=INF;//记得初始化;
for(int j=1;j<=M;j++){//找最小权值;
if(!vis[j]&&temp>low[j]){
temp=low[k=j];
}
}
if(temp==INF){//找不到就判断;
if(flot!=M)puts("?");
else printf("%d\n",min);
break;
}
min+=temp;
flot++;//代表当前已选集合中的元素个数;
vis[k]=1;
for(int i=1;i<=M;i++){//更新low数组;使其与已选数组相连的权值小;
if(!vis[i]&&low[i]>map[k][i])
low[i]=map[k][i];
}
}
}
int main(){
int a,b,d;
while(~scanf("%d%d",&N,&M),N){
min=0;//刚开始min忘初始化了。。。
memset(map,INF,sizeof(map));//INF初始化为0xfffffff就不行,都是-1了
//for(int i=0;i<10;i++)for(int j=0;j<10;j++)printf("%d ",map[i][j]);
for(int i=0;i<N;i++){
scanf("%d%d%d",&a,&b,&d);
if(d<map[a])//此处不能少。。。
map[a][b]=map[b][a]=d;
}
prime();
}
return 0;
}


畅通工程再续

[b]Time Limit : 2000/1000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other)

Total Submission(s) : 46 Accepted Submission(s) : 20
[align=left]Problem Description[/align]
相信大家都听说一个“百岛湖”的地方吧,百岛湖的居民生活在不同的小岛中,当他们想去其他的小岛时都要通过划小船来实现。现在政府决定大力发展百岛湖,发展首先要解决的问题当然是交通问题,政府决定实现百岛湖的全畅通!经过考察小组RPRush对百岛湖的情况充分了解后,决定在符合条件的小岛间建上桥,所谓符合条件,就是2个小岛之间的距离不能小于10米,也不能大于1000米。当然,为了节省资金,只要求实现任意2个小岛之间有路通即可。其中桥的价格为 100元/米。

[align=left]Input[/align]
输入包括多组数据。输入首先包括一个整数T(T <= 200),代表有T组数据。每组数据首先是一个整数C(C <= 100),代表小岛的个数,接下来是C组坐标,代表每个小岛的坐标,这些坐标都是 0 <= x, y <= 1000的整数。

[align=left]Output[/align]
每组输入数据输出一行,代表建桥的最小花费,结果保留一位小数。如果无法实现工程以达到全部畅通,输出”oh!”.

[align=left]Sample Input[/align]

2 2 10 10 20 20 3 1 1 2 2 1000 1000

[align=left]Sample Output[/align]

1414.2 oh!
题解:qsort写错了,wa了无数次;也可以设个变量num=1;每加进一个点或者一个树时就num++最后与n比较,相等则连通;
代码一:克鲁斯卡尔

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
double distant(int ax,int ay,int bx,int by){
int x=bx-ax,y=by-ay;
double s;
s=x*x+y*y;
s=sqrt(s);
return s;
}
int pre[110];
struct Node{
int s,e;
double d;
};
Node die[10010];
int find(int x){
return pre[x]= x==pre[x]?x:find(pre[x]);
}
double minmoney;
int cmp(const void *a,const void *b){
if((*(Node *)a).d<(*(Node *)b).d)return -1;
else return 1;
}
void merge(Node a){
if(pre[a.s]==-1)pre[a.s]=a.s;
if(pre[a.e]==-1)pre[a.e]=a.e;
int f1=find(a.s),f2=find(a.e);
if(f1!=f2){
pre[f1]=f2;
minmoney+=a.d;
}
}
void initial(){
memset(pre,-1,sizeof(pre));
memset(die,0,sizeof(die));
}
int nx[110],ny[110];
int main(){
int T,C;
scanf("%d",&T);
while(T--){minmoney=0;
initial();
// for(int i=0;i<110;i++)printf("%d",pre[i]);
scanf("%d",&C);
for(int i=0;i<C;i++){
scanf("%d%d",&nx[i],&ny[i]);
}
int k=0;
for(int i=0;i<C;i++){
for(int j=i+1;j<C;j++){
double dis=distant(nx[i],ny[i],nx[j],ny[j]);
//printf("%lf  ",dis);
if(dis>=10&&dis<=1000){
die[k].s=i;die[k].e=j;
die[k].d=dis;
k++;
}
}
}
//printf("%d\n",k);
qsort(die,k,sizeof(die[0]),cmp);
for(int i=0;i<k;i++){
merge(die[i]);
}
int flot=0;
for(int i=0;i<C;i++){
if(pre[i]==i||pre[i]==-1)flot++;
//if(flot>1)break;
}
//printf("%d\n",flot);
if(flot>1) puts("oh!");
else printf("%.1lf\n",minmoney*100);
}
return 0;
}


代码二:

无语,又错了好久,然后发现初始化map出错,对于double数组不能像int那样初始化;

代码:

#include<stdio.h>
#include<string.h>
#include<math.h>
const int INF=0x3f3f3f3f;
const int MAXN=110;
int N,vis[MAXN];
double map[MAXN][MAXN],low[MAXN];
double fd(int ax,int ay,int bx,int by){
int x=bx-ax;
int y=by-ay;
int s=x*x+y*y;
return sqrt(s);
}
void prime(){
int flot=1,k;
double min=0,temp;
memset(vis,0,sizeof(vis));
vis[0]=1;
for(int i=0;i<N;i++)
{low[i]=map[0][i];}
//printf("low  %lf \n",low[i]);}
for(int i=0;i<N;i++){
temp=INF;
for(int j=0;j<N;j++){
if(!vis[j]&&low[j]<temp)
temp=low[k=j];
}
// printf("***%d   %lf  ",temp,min);
if(temp==INF){
if(flot==N)printf("%.1lf\n",min*100);
else puts("oh!");
break;
}
min+=temp;
flot++;
vis[k]=1;
for(int j=0;j<N;j++){
if(!vis[j]&&low[j]>map[k][j])
low[j]=map[k][j];
}
}
}
int main(){
int T;
int dx[MAXN],dy[MAXN];
scanf("%d",&T);
while(T--){
for(int i=0;i<MAXN;i++)
for(int j=0;j<MAXN;j++)
map[i][j]=INF;
scanf("%d",&N);
for(int i=0;i<N;i++)
scanf("%d%d",&dx[i],&dy[i]);
for(int i=0;i<N;i++)
for(int j=i+1;j<N;j++){
double dis=fd(dx[i],dy[i],dx[j],dy[j]);
//printf("### %d  %d %lf  ",i,j,dis);
if(dis<map[i][j]&&dis>=10&&dis<=1000)
map[i][j]=map[j][i]=dis;
}
/*for(int i = 0; i < N; ++i)
printf("%lf\n", map[0][i]);*/
prime();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: