cf472D Design Tutorial: Inverse the Problem

D. Design Tutorial: Inverse the Problem
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

There is an easy way to obtain a new task from an old one called "Inverse the problem": we give an output of the original task, and ask to generate an input, such that solution to the original problem will produce the output we provided. The hard task of Topcoder Open 2014 Round 2C, InverseRMQ, is a good example.

Now let's create a task this way. We will use the task: you are given a tree, please calculate the distance between any pair of its nodes. Yes, it is very easy, but the inverse version is a bit harder: you are given an n × n distance matrix. Determine if it is the distance matrix of a weighted tree (all weights must be positive integers).

Input

The first line contains an integer n (1 ≤ n ≤ 2000) — the number of nodes in that graph.

Then next n lines each contains n integers di, j (0 ≤ di, j ≤ 109) — the distance between node i and node j.

Output

If there exists such a tree, output "YES", otherwise output "NO".

Sample test(s)
input
3
0 2 7
2 0 9
7 9 0
output
YES
input
3
1 2 7
2 0 9
7 9 0
output
NO
input
3
0 2 2
7 0 9
7 9 0
output
NO
input
3
0 1 1
1 0 1
1 1 0
output
NO
input
2
0 0
0 0
output
NO
Note

In the first example, the required tree exists. It has one edge between nodes 1 and 2 with weight 2, another edge between nodes 1 and 3 with weight 7.

In the second example, it is impossible because d1, 1 should be 0, but it is 1.

In the third example, it is impossible because d1, 2 should equal d2, 1.


我對於暴力出奇跡又有了更深的理解……

題意是給你一個dist[i][j]的鄰接矩陣,判斷這是不是一棵樹。

想法是先假設這就是棵樹,用最小生成樹直接算出應有的n-1條邊,然後暴力求出在只有這n-1條邊的情況下的dist和原數組比較

當然前面還要預處理排除一堆不合法答案

這題n=2000就是400w的邊,再加點處理也有200w邊,明顯稠密圖,應該用Prim,居然Kruskal能過……服了

貼代碼……

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<deque>
#include<set>
#include<map>
#include<ctime>
#define LL long long
#define inf 2147483647
#define pa pair<int,int>
#define N 2100
using namespace std;
struct bian{
	int x,y,z;
}b[2000010];
bool operator < (const bian &a,const bian &b)
{
	return a.z<b.z;
}
struct edge{
	int to,next,v;
}e[10*N];int head[N];
LL n,cnt,tot;
LL a[N][N];
int fa[N];
int top,zhan[N];bool vis[N];
LL dist[N][N];
inline int getfa(int x)
{return fa[x]==x?x:fa[x]=getfa(fa[x]);}
inline void ins(int u,int v,int w)
{
	e[++cnt].to=v;
	e[cnt].next=head[u];
	e[cnt].v=w;
	head[u]=cnt;
}
inline void insert(int u,int v,int w)
{
	ins(u,v,w);
	ins(v,u,w);
}
inline LL read()
{
    LL x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
inline void init()
{
	n=read();
	for (int i=1;i<=n;i++)
	  for (int j=1;j<=n;j++)
	    a[i][j]=read();
}
inline bool pre_judge()
{
	for (int i=1;i<=n;i++)
	  for(int j=1;j<=n;j++)
	  {
	  	if (i==j&&a[i][i]!=0)return 0;
	  	if (i!=j&&a[i][j]==0)return 0;
	  	if (a[i][j]!=a[j][i])return 0;
	  }
	return 1;
}
inline void Kruskal()
{
	for (int i=1;i<=n;i++)fa[i]=i;
	for (int i=1;i<=n;i++)
	  for(int j=1;j<=n;j++)
	    if (i<j)
		{
			b[++tot].x=i;
			b[tot].y=j;
			b[tot].z=a[i][j];
		}
	sort(b+1,b+tot+1);
	int piece=n;
	for (int i=1;i<=tot;i++)
	  {
	  	int fx=getfa(b[i].x);
	  	int fy=getfa(b[i].y);
	  	if (fx==fy)continue;
	  	piece--;
	  	fa[fx]=fy;
	  	insert(b[i].x,b[i].y,b[i].z);
	  	if (piece==1)return;
	  }
}
inline void dfs(int cur)
{
	for (int i=head[cur];i;i=e[i].next)
	{
		if (vis[e[i].to])continue;
		for (int j=1;j<=top;j++)
		{
			dist[e[i].to][zhan[j]]=dist[zhan[j]][e[i].to]=dist[zhan[j]][cur]+e[i].v;
		}
		zhan[++top]=e[i].to;
		vis[e[i].to]=1;
		dfs(e[i].to);
	}
}
int main()
{
	init();
	if (!pre_judge())
	{
		printf("NO");
		return 0;
	}
	Kruskal();
	zhan[1]=1;top=1;vis[1]=1;
	dfs(1);
	for (int i=1;i<=n;i++)
	  for(int j=1;j<=n;j++)
	    if(a[i][j]!=dist[i][j])
	    {
	    	printf("NO");
	    	return 0;
	    }
	printf("YES");
	return 0; 
}

以下Prim版(第一次寫,有點銼,神犇別D我)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<deque>
#include<set>
#include<map>
#include<ctime>
#define LL long long
#define inf 2147483647
#define pa pair<int,int>
#define N 2100
using namespace std;
struct edge{
	int to,next,v;
}e[10*N];int head[N];
LL n,cnt;
LL a[N][N];//讀入的距離 
bool inset[N];//是否在MST集合中 
pa dis[N]; //二元組dist[k]=(i,j)表示從所有在集合中的點到k的最短邊是從j到k,權爲=i
int top,zhan[N];bool vis[N];//MST之後處理dist的dfs用 
LL dist[N][N];//最後算出來的dist 
inline void ins(int u,int v,int w)
{
	e[++cnt].to=v;
	e[cnt].next=head[u];
	e[cnt].v=w;
	head[u]=cnt;
}
inline void insert(int u,int v,int w)
{
	ins(u,v,w);
	ins(v,u,w);
}
inline LL read()
{
    LL x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
inline bool pre_judge()
{
	for (int i=1;i<=n;i++)
	  for(int j=1;j<=n;j++)
	  {
	  	if (i==j&&a[i][i]!=0)return 0;
	  	if (i!=j&&a[i][j]==0)return 0;
	  	if (a[i][j]!=a[j][i])return 0;
	  }
	return 1;
}
inline void init()
{
	n=read();
	for (int i=1;i<=n;i++)
	  for (int j=1;j<=n;j++)
	    a[i][j]=read();
}
inline void prim()
{
	int cur=1;inset[1]=1;
	for (int i=2;i<=n;i++)
	{
	  dis[i].first=a[1][i];
	  dis[i].second=1;
	}
	for (int i=1;i<n;i++)
	{
		LL mn=inf;
		int from=0;
		for (int j=1;j<=n;j++)
		  if (!inset[j]&&dis[j].first<mn)
		  {
		  	mn=dis[j].first;
		  	from=dis[j].second;
		  	cur=j;
		  }
		insert(from,cur,mn);
		inset[cur]=1;
		for (int j=1;j<=n;j++)
		  if (!inset[j]&&a[cur][j]<dis[j].first)
		  {
		  	dis[j].first=a[cur][j];
		  	dis[j].second=cur;
		  }
	}
}
inline void dfs(int cur)
{
	for (int i=head[cur];i;i=e[i].next)
	{
		if (vis[e[i].to])continue;
		for (int j=1;j<=top;j++)
		{
			dist[e[i].to][zhan[j]]=dist[zhan[j]][e[i].to]=dist[zhan[j]][cur]+e[i].v;
		}
		zhan[++top]=e[i].to;
		vis[e[i].to]=1;
		dfs(e[i].to);
	}
}
int main()
{
	init();
	if (!pre_judge())
	{
		printf("NO");
		return 0;
	}
	prim();
	zhan[1]=1;top=1;vis[1]=1;
	dfs(1);
	for (int i=1;i<=n;i++)
	  for(int j=1;j<=n;j++)
	    if(a[i][j]!=dist[i][j])
	    {
	    	printf("NO");
	    	return 0;
	    }
	printf("YES\n");
	return 0; 
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章