(o(╯□╰)o还是很不习惯国外的区域赛题目。。。读不是很懂啊不是很懂啊。。。要研究半天)
Absurdistan Roads
Time Limit: 5678/3456MS (Java/Others) Memory Limit: 65432/65432KB (Java/Others)
Submit
Status
The people of Absurdistan discovered how to build roads only last year. After the discovery, every city decided to build their own road connecting their city with another city. Each newly built road can be used
in both directions.
Absurdistan is full of surprising coincidences. It took all N cities
precisely one year to build their roads. And even more surprisingly, in the end it was possible to travel from every city to every other city using the newly built roads.
You bought a tourist guide which does not have a map of the country with the new roads. It only contains a huge table with the shortest distances between all pairs of cities using the newly built roads. You would
like to know between which pairs of cities there are roads and how long they are, because you want to reconstruct the map of the N newly
built roads from the table of shortest distances.
You get a table of shortest distances between all pairs of cities in Absurdistan using the N roads
built last year. From this table, you must reconstruct the road network of Absurdistan. There might be multiple road networks with N roads
with that same table of shortest distances, but you are happy with any one of those networks.
Input
For each test case:
- A line containing an integer N (2≤N≤2000) --
the number of cities and roads. - N lines
with N numbers
each. The j-th
number of the i-th
line is the shortest distance from city i to
city j.
All distances between two distinct cities will be positive and at most 1000000.
The distance from i to i will
always be 0 and
the distance from i to j will
be the same as the distance from j to i.
Output
For each test case:
- Print N lines
with three integers ‘a b c‘
denoting that there is a road between cities 1≤a≤N and 1≤b≤N of
length 1≤c≤1000000,
wherea≠b.
If there are multiple solutions, you can print any one and you can print the roads in any order. At least one solution is guaranteed to exist.
Print a blank line between every two test cases.
Sample input and output
Sample Input | Sample Output |
---|---|
4 0 1 2 1 1 0 2 1 2 2 0 1 1 1 1 0 4 0 1 1 1 1 0 2 2 1 2 0 2 1 2 2 0 3 0 4 1 4 0 3 1 3 0 |
2 1 1 4 1 1 4 2 1 4 3 1 2 1 1 3 1 1 4 1 1 2 1 1 3 1 1 2 1 4 3 2 3 |
Source
Northwestern European Regional Contest 2013
题意:
就是给一张n个点的矩阵,pos[i][j]表示i和j之间的最短距离。要你将新建的道路满足这个table最短距离描述
的n条所建的边输出且保证这些边权是最小的。
算法:
先用kruscal找到最小的n-1条边把所有点连通,这n-1条边是肯定符合要求的。然后利用这n-1条边的边权用
floyd求n个点两两之间能形成的最短路。再把边从小到大扫描,如果与table中的最短路不符,则为第n条要建的
边,否则就从前n-1条边中任意输出一条。
有几个地方要注意剪枝,不然特别容易TLE。。。
1、从第n-1条(由于我存边的编号从0开始,即为编号n-2的边)开始判断是否相符。
2、floyd要判断if(mp2[i][k]==INF) 直接break。
3、kruscal那个从0-cnt的遍历哟。。。到了c==n-1就可以break了。。。
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #define INF 0x3f3f3f3f #define maxn 2010 using namespace std; int mp[maxn][maxn],n,cnt,fa[maxn],mp2[maxn][maxn]; bool vis[maxn][maxn]; struct node { int u,v,w; }e[maxn*maxn],ans[maxn+10]; void add(int x,int y,int z) { e[cnt].u = x; e[cnt].v = y; e[cnt++].w = z; } bool cmp(node x,node y) { return x.w<y.w; } int find(int x) { return fa[x]==x?x:find(fa[x]); } void init() { for(int i=1;i<=n;i++) fa[i] = i; cnt = 0; } bool merge(int a,int b) { int fx = find(a); int fy = find(b); if(fx!=fy) { fa[fx] = fy; return true; } else return false; } void krus() { int c = 0; sort(e,e+cnt,cmp); for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { if(i==j) mp2[i][j] = 0; else mp2[i][j] = INF; } } for(int i=0;i<cnt;i++) { if(merge(e[i].u,e[i].v)) { ans[c].u = e[i].u; ans[c].v = e[i].v; ans[c++].w = e[i].w; int ta = e[i].u,tb = e[i].v,tc = e[i].w; mp2[ta][tb] = mp2[tb][ta] = tc; } if(c==n-1) break; } for(int k=1;k<=n;k++) { for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { if(mp2[i][k]==INF) break; mp2[i][j] = min(mp2[i][j],mp2[i][k]+mp2[k][j]); } } } int ok = 0; for(int i=n-2;i<cnt;i++) { int ta = e[i].u,tb = e[i].v,tc = e[i].w; if(mp2[ta][tb]!=tc) { ans[c].u = ta; ans[c].v = tb; ans[c++].w = tc; } } if(!ok) { ans[c].u = e[0].u; ans[c].v = e[0].v; ans[c++].w = e[0].w; } for(int i=0;i<n;i++) printf("%d %d %d\n",ans[i].u,ans[i].v,ans[i].w); } int main() { int sign = 0; while(scanf("%d",&n)!=EOF) { if(!sign) sign = 1; else printf("\n"); init(); 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=1;j<i;j++) { add(i,j,mp[i][j]); } } krus(); } return 0; }