解题报告2

来源:互联网 发布:文字转word软件 编辑:程序博客网 时间:2024/05/19 18:39

find the mincost route

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


Problem Description
杭州有N个景区,景区之间有一些双向的路来连接,现在8600想找一条旅游路线,这个路线从A点出发并且最后回到A点,假设经过的路线为V1,V2,....VK,V1,那么必须满足K>2,就是说至除了出发点以外至少要经过2个其他不同的景区,而且不能重复经过同一个景区。现在8600需要你帮他找一条这样的路线,并且花费越少越好。
 

Input
第一行是2个整数N和M(N <= 100, M <= 1000),代表景区的个数和道路的条数。
接下来的M行里,每行包括3个整数a,b,c.代表a和b之间有一条通路,并且需要花费c元(c <= 100)。
 

Output
对于每个测试实例,如果能找到这样一条路线的话,输出花费的最小值。如果找不到的话,输出"It's impossible.".
 

Sample Input
3 31 2 12 3 11 3 13 31 2 11 2 32 3 1
 

Sample Output
3It's impossible.
 

Author
8600
 

Source
HDU 2007-Spring Programming Contest - Warm Up (1)
 

Recommend
8600   |   We have carefully selected several similar problems for you:  1595 1598 1596 1142 1217 

这个题用Floyd来写需要设置两个二维数组,一个用来存原始的边,另一个用来存Floyd不断更新后的两点之间的当前最短距离,其实求最小环就是在更新过程中,加入一个二重循环判断是否存在一个之前没用过的点k能使i,j联通,并不断寻找满足条件的最小值。

#include<cstdio>            //Floyd求最小环#include<iostream>#include<cstring>#include<algorithm>#define N 109#define inf  2147483647/3 using namespace std;int  n,m,k,ans;int  maze[N][N],dist[N][N];void floyd(){    int i,j,k;    ans = inf;    for(k=1;k <= n;k++)    {        for(i=1;i < k;i++)            for(j=i+1;j < k;j++)                if(ans > dist[i][j] + maze[i][k] + maze[j][k])                {                    ans = dist[i][j] + maze[i][k] + maze[j][k];                }        for(i=1;i <= n;i++)            for(j=1;j <= n;j++)                if(i-k && j-k && i-j && dist[i][j] > dist[i][k]+dist[k][j])                {                    dist[i][j] = dist[i][k]+dist[k][j];                }    }}int main(){    int i,j,st,en,len;    while(scanf("%d%d",&n,&m)!=EOF)    {        for(i=1;i <= n;i++)            for(j=1;j <= n;j++)            {                maze[i][j] = dist[i][j] = inf;            }        while(m--)        {            scanf("%d%d%d",&st,&en,&len);            if(st-en && dist[st][en] > len)                dist[st][en]=dist[en][st]=maze[st][en]=maze[en][st]=len;        }        floyd();    if(ans == inf)        printf("It's impossible.\n");    else        printf("%d\n",ans);    }return 0;}


还是畅通工程

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 38610    Accepted Submission(s): 17477


Problem Description
某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离。省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可),并要求铺设的公路总长度为最小。请计算最小的公路总长度。
 

Input
测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( < 100 );随后的N(N-1)/2行对应村庄间的距离,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间的距离。为简单起见,村庄从1到N编号。
当N为0时,输入结束,该用例不被处理。
 

Output
对每个测试用例,在1行里输出最小的公路总长度。
 

Sample Input
31 2 11 3 22 3 441 2 11 3 41 4 12 3 32 4 23 4 50
 

Sample Output
35
Hint
Hint
Huge input, scanf is recommended.
 

Source
浙大计算机研究生复试上机考试-2006年
 

Recommend
JGShining   |   We have carefully selected several similar problems for you:  1232 1875 1879 1301 1162 


这个题只要理解了prim算法就可以直接过了,标准的最小生成树

#include <iostream>                            //prim最小生成树#include<cstdio>#include<cstring>#define inf 9999999 using namespace std;int n,m,d[105][105],low[105],vis[105];int prim(){    int i,j,k,minx,ans=0;    memset(vis,0,sizeof(vis));    memset(low,inf,sizeof(low));    for(i=2;i<=n;i++)        low[i]=d[1][i];    vis[1]=1;    for(i=2;i<=n;i++)    {        minx=inf;        j=k=2;        while(j<=n)        {            if(!vis[j]&&low[j]<minx)                minx=low[k=j];            j++;        }        if(minx==inf)            return -1;        ans+=low[k];        vis[k]=1;        for(j=2;j<=n;j++)            if(low[j]>d[k][j])            low[j]=d[k][j];    }    return ans;}int main(){    int u,v,w,i;    while(scanf("%d",&n))    {        if(n==0)            break;        memset(d,inf,sizeof(d));        for(i=0;i<n*(n-1)/2;i++)        {            scanf("%d%d%d",&u,&v,&w);            if(d[u][v]>w)                d[u][v]=d[v][u]=w;        }        printf("%d\n",prim());    }    return 0;}



Constructing Roads

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 20197    Accepted Submission(s): 7725


Problem Description
There are N villages, which are numbered from 1 to N, and you should build some roads such that every two villages can connect to each other. We say two village A and B are connected, if and only if there is a road between A and B, or there exists a village C such that there is a road between A and C, and C and B are connected. 

We know that there are already some roads between some villages and your job is the build some roads such that all the villages are connect and the length of all the roads built is minimum.
 

Input
The first line is an integer N (3 <= N <= 100), which is the number of villages. Then come N lines, the i-th of which contains N integers, and the j-th of these N integers is the distance (the distance should be an integer within [1, 1000]) between village i and village j.

Then there is an integer Q (0 <= Q <= N * (N + 1) / 2). Then come Q lines, each line contains two integers a and b (1 <= a < b <= N), which means the road between village a and village b has been built.
 

Output
You should output a line contains an integer, which is the length of all the roads to be built such that all the villages are connected, and this value is minimum. 
 

Sample Input
30 990 692990 0 179692 179 011 2
 

Sample Output
179
 

Source
kicc
 

Recommend
Eddy   |   We have carefully selected several similar problems for you:  1301 1162 1232 1875 1879 

这个题比上一个就要稍微难一些了,我之前用prim做的时候犯了一个低级错误(在while循环输入n时忘了写文件结束标志)导致超时,然后我又用kruskal来写,结果超内存了,经过请教别人和自己认真琢磨最后明白了错在何处,用kruskal时,不是把边的值改为0,而是应该要把两个点连到同一个父节点上,之后还是有错误,因为统计有效边的m忘了每轮循环后要更新。

#include<cstdio>         //Constructing Roads Kruskal算法#include<algorithm>#include<cstring>#include<iostream>using namespace std; int n,m,fa[210];int Find(int x){if(fa[x]!=x)fa[x]=Find(fa[x]);return fa[x];} struct node{int u,v,w;}e[120005];bool cmp(const node &n1,const node &n2){    return n1.w < n2.w;}int Kruskal(){int i,x,y,ans=0;sort(e,e+m,cmp);for(i=0;i<m;i++){x=Find(e[i].u);y=Find(e[i].v);if(x!=y){fa[x]=y;ans+=e[i].w;}}return ans;}int main(){int wx;while(scanf("%d",&n)!=EOF){    m=0;                              //统计有效边的个数,需要更新for(int i=1;i<=n;i++)        {            for(int j=1;j<=n;j++)            {scanf("%d",&wx);if(i<j){e[m].u=i;e[m].v=j;e[m].w=wx;m++;}            }        }        for(int i=1;i<=n;i++)        {             fa[i]=i;        }        int q,a,b;        scanf("%d",&q);        while(q--)        {            scanf("%d%d",&a,&b);            a=Find(a);            b=Find(b);            fa[b]=a;                                                //把两个点连到同一个父节点上        }        printf("%d\n",Kruskal());}return 0;}


#include <iostream>               //Constructing Roads Prim算法#include<cstdio>#include<cstring>#define inf 0x3fffffff using namespace std;int n,m,d[105][105],low[105],vis[105];int prim(){    int i,j,k,minx,ans=0;    memset(vis,0,sizeof(vis));memset(low,inf,sizeof(low));    for(i=2;i<=n;i++)        low[i]=d[1][i];    vis[1]=1;    for(i=2;i<=n;i++)    {        minx=inf;        j=k=2;        while(j<=n)        {            if(!vis[j]&&low[j]<minx)                minx=low[k=j];            j++;        }        if(minx==inf)            return -1;        ans+=low[k];        vis[k]=1;        for(j=2;j<=n;j++)            if(low[j]>d[k][j])            low[j]=d[k][j];    }    return ans;}int main(){    int u,v,i,j,q;    while(~scanf("%d",&n))                                            //需要文件结束标志    {        memset(d,inf,sizeof(d));        for(i=1;i<=n;i++)        {            for(j=1;j<=n;j++)            scanf("%d",&d[i][j]);        }        scanf("%d",&q);        while(q--)        {            scanf("%d%d",&u,&v);            d[u][v]=d[v][u]=0;        }        printf("%d\n",prim());    }    return 0;}



Intervals

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 3623    Accepted Submission(s): 1329


Problem Description
You are given n closed, integer intervals [ai, bi] and n integers c1, ..., cn.

Write a program that:

> reads the number of intervals, their endpoints and integers c1, ..., cn from the standard input,

> computes the minimal size of a set Z of integers which has at least ci common elements with interval [ai, bi], for each i = 1, 2, ..., n,

> writes the answer to the standard output
 

Input
The first line of the input contains an integer n (1 <= n <= 50 000) - the number of intervals. The following n lines describe the intervals. The i+1-th line of the input contains three integers ai, bi and ci separated by single spaces and such that 0 <= ai <= bi <= 50 000 and 1 <= ci <= bi - ai + 1.

Process to the end of file.

 

Output
The output contains exactly one integer equal to the minimal size of set Z sharing at least ci elements with interval [ai, bi], for each i = 1, 2, ..., n.
 

Sample Input
53 7 38 10 36 8 11 3 110 11 1
 

Sample Output
6
 

Author
1384
 

Recommend
Eddy   |   We have carefully selected several similar problems for you:  1529 1531 1548 1534 1317 

这个题刚开始题都看不懂,完全不知道要算的是什么,后来讲过之后才理解了题意,然后也不会写,看过学长的程序后,现在才算是真的懂了这个题了,spfa中用到了先进先出的队列,最开始的时候只把源点压入队列中,并且用一个数组来存从源点到其他每个点的距离,最初设置的距离都是INF,源点到自己的距离是0,然后取出队首的点计算到其他每个点的距离是否小于当前的距离,是则更新,并判断这个点是否在队列中,如果不在则把他压入队尾,如果一个点被压入队列超过了n次则说明存在有负值的环。因为这个题没有说有环的情况,所以可以不用判环。

#include<cstdio>                 //差分约束spfa算法#include<iostream>#include<queue>#include<cstring>#include<algorithm>#define N 51000#define inf 1e9 using namespace std;int num,p[N],n;struct node{    int en,len,next;}edg[N*10];void add(int st,int en,int len){    edg[num].en=en;    edg[num].len=len;    edg[num].next=p[st];    p[st]=num++;}queue<int>que;bool inque[N];int dis[N];void spfa(int st,int en){    for(int i=0;i<=en;i++)    {        dis[i]=-inf;        inque[i]=false;    }    que.push(st);    dis[st]=0;    inque[st]=true;    while(que.size())    {    int x=que.front();    que.pop();    inque[x]=false;    for(int i=p[x];i!=-1;i=edg[i].next)    {        int y=edg[i].en;        if(dis[x]+edg[i].len>dis[y])        {            dis[y]=dis[x]+edg[i].len;            if(!inque[y])            {                que.push(y);                inque[y]=true;            }        }    }    }}int main(){    while(~scanf("%d",&n))    {        num=0;        memset(p,-1,sizeof(p));        int st=inf,en=-1;        for(int i=1;i<=n;i++)        {            int a,b,c;            scanf("%d%d%d",&a,&b,&c);            add(a,b+1,c);            st=min(st,a);            en=max(en,b+1);        }        for(int i=st;i<=en;i++)        {            add(i,i-1,-1);            add(i-1,i,0);        }        spfa(st,en);        printf("%d\n",dis[en]);    }    return 0;}

0 0
原创粉丝点击