您的位置:首页 > 运维架构

2013-2014 Northwestern European Regional Contest (NWERC 2013)

2016-09-07 21:31 671 查看
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

;
bool is

;
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

, father
, dep
,root
;
vector<int> vet
;
bool vis
;
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
;
int arr
,ans,path
;
bool is

,vis
;
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

两种日历的表示方法,同时对应着两种计算闰年的方式。问之前日历的日期对应现在日历的日期。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐