2013-2014 Northwestern European Regional Contest (NWERC 2013)

来源:互联网 发布:linux ftp命令 prompt 编辑:程序博客网 时间:2024/05/16 14:15

http://codeforces.com/gym/100405/

补题:

A

已知一个图的点数为n,且改图为连通图。告诉了每两个点之间的最短路的距离。让你构造这个图,且这个图的边数为n。

Idea 1:
删边法。时间接近于O(n^3 )。根据题目中给的矩阵构造一个完全图,然后遍历每条边,看是否需这条边是多余的。如果某条边的两点间的最短路可以由其他点到达,那么这条边就是多余的,可删除。因为保证有解,所以最后这张图里面要么有n条边,要么有n-1条边。最后处理一下即可。

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int N = 2050;int mp[N][N];bool is[N][N];int main(){        int n;        bool flag = false;        while(scanf("%d",&n)!=EOF)        {                if(flag) printf("\n");                flag = true;                memset(is,true,sizeof(is));                for(int i=1;i<=n;i++)                        for(int j=1;j<=n;j++)                                scanf("%d",&mp[i][j]);                for(int i=1;i<=n;i++)                {                        for(int j=i+1;j<=n;j++)                        {                                for(int k=1;k<=n;k++)                                {                                        if(k==i || k==j) continue;                                        if(mp[i][j] == mp[i][k]+mp[k][j])                                        {                                                is[i][j] = false;                                                break;                                        }                                }                        }                }                int cnt = 0;                for(int i=1;i<=n;i++)                {                        for(int j=i+1;j<=n;j++)                        {                                if( is[i][j])                                 {                                        printf("%d %d %d\n",i,j,mp[i][j]);                                        cnt ++;                                }                        }                }                if(cnt==n -1) printf("%d %d %d\n",1,2,mp[1][2]);        }        return 0;}

Idea2:
将所有的边排序然后做一次最小生成树,O(nlogn)。然后最后在这个图上加一条边。先DFS遍历这个图,计算两点的距离,看是否是最短路。如果是不是最短路,增加本应该最短的那条路。

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <vector>using namespace std;const int N = 2050;struct Node{        int u,v,x;        Node(){}        Node(int a,int b,int c):u(a),v(b),x(c){}        friend bool operator < (const Node a,const Node b)        {                return a.x < b.x;        }}edg[N*N];int gra[N][N], father[N], dep[N],root[N];vector<int> vet[N];bool vis[N];int find(int x){        int y = x;        while(y!=father[y]) y = father[y];        while(x!=father[x])        {                int px = father[x];                father[x] = y;                x = px;        }        return y;}void dfs(int u,int time,int fa){       dep[u] = time;       root[u] = fa;       vis[u] = true;       for(int i=0; i<vet[u].size();i++)        {                int v = vet[u][i];                if(vis[v]) continue;                dfs(v,time+1,u);       }}int LCA(int x,int y){        int tmp = 0;        while(x != y )        {                if(dep[x] > dep[y])                {                    int px = x;                    x = root[x];                    tmp += gra[px][x];                }                else                 {                    int py = y;                    y = root[y];                    tmp+=gra[py][y];                }        }        return tmp;}int main(){        int n;        bool flag = false;        while(scanf("%d",&n)!=EOF)        {                if(flag) printf("\n");                flag = true;                int tot = 0;                for(int i=1;i<=n;i++)                {                        father[i] = i;                        root[i] = i;                        vet[i].clear();                        for(int j=1;j<=n;j++)                        {                                scanf("%d",&gra[i][j]);                                if(i>j) edg[tot++] = Node(i,j,gra[i][j]);                        }                }                sort(edg,edg+tot);                for(int i=0; i<tot;i++)                {                        int x = edg[i].u;                        int y = edg[i].v;                        int fx = find(x);                        int fy = find(y);                        if(fx==fy) continue;                        father[fx] = fy;                        vet[x].push_back(y);                        vet[y].push_back(x);                        printf("%d %d %d\n",x,y,edg[i].x);                }                memset(vis,false,sizeof(vis));                     dfs(1,0,1);                int ans = 0x3f3f3f3f, x=1 , y=2;                for(int i=1;i<=n;i++)                {                        for(int j=i+1;j<=n;j++)                        {                                int dis =  LCA(i,j);                                if(dis == gra[i][j]) continue;                                if( gra[i][j] < ans)  ans = gra[i][j], x = i, y = j;                        }                }                printf("%d %d %d\n",x,y,gra[x][y]);        }        return 0;}

B

给一个无向图,每个节点都有个权值。找出该图的一个最大团,且最大团内保证路径没有交叉。

DFS爆搜即可。因为符合情况的最大团只有三种情况,要么两个点,要么三个点,要么四个点。。

#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>#include <vector>using namespace std;const int N = 500;vector<int> vet[N];int arr[N],ans,path[N];bool is[N][N],vis[N];void dfs(int u,int id,int nans){    ans = max(ans,nans);    if( id >=4 ) return;    for(int i=0; i<vet[u].size();i++)    {        int v = vet[u][i], j;        if(vis[v]) continue;        for(j=1;j<=id;j++)         {            if(!is[v][path[j]]) break;        }        if(j<=id) continue;        vis[v] = true;        path[id+1] = v;        dfs(v,id+1,nans+arr[v]);         vis[v] = false;    }    return;}int main(){    int n,m;    while(scanf("%d%d",&n,&m)!=EOF)    {        for(int i=1;i<=n;i++) scanf("%d",&arr[i]),vet[i].clear();        memset(is,false,sizeof(is));        for(int i=1;i<=m;i++)        {            int u,v;            scanf("%d%d",&u,&v);            vet[u].push_back(v);            vet[v].push_back(u);            is[u][v] = is[v][u] = true;        }        ans = 0;         for(int i=1;i<=n;i++)        {            memset(vis,false,sizeof(vis));            vis[i] = true;            path[1] = i;            dfs(i,1,arr[i]);        }        printf("%d\n",ans);    }    return 0;}

G

水。

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;int gcd(int a,int b){     return b==0?a:gcd(b,a%b);}int main(){    int a,b,c;    while (~scanf("%d%d%d",&a,&b,&c)){        int x=a*b;        int y=c-b;        //cout<<x<<" "<<y<<endl;        int w=gcd(x,y);        printf("%d/%d\n",x/w,y/w);    }    return 0;}

F

两种日历的表示方法,同时对应着两种计算闰年的方式。问之前日历的日期对应现在日历的日期。

0 0
原创粉丝点击