zoukankan      html  css  js  c++  java
  • 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和原数组比较

    当然前面还要预处理排除一堆不合法答案

    hzwer:为什么要做最小生成树呢?因为首先距离当前点x最近的点y肯定是有边直接连接的,因为(反证法)假设有z使得xz和yz分别连接,则dis[x][z]+dis[y][z]<=dis[x][y],所以应该有dis[x][z]<dis[x][y],与已知条件dist[x][y]最小不符

    所以我们要优先考虑边权小的边,所以直接最小生成树

    这题n=2000就是400w的边,再加点处理也有200w边,明显稠密图,应该用Prim,居然Kruskal能过……服了

    贴代码……

    以下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
    ");
    	return 0; 
    }
    

      

    ——by zhber,转载请注明来源
  • 相关阅读:
    【转载】ASP.NET MVC中Controller与View之间的数据传递总结
    [转载]ASP.NET MVC 2配置使用CKEditor编辑器
    一步一步学NUnit(1)
    js关闭窗口弹出对话框
    [转载]将ASP.NET MVC 2.0 部署在IIS6和IIS7上的教程
    [转载] HTTP MIME
    【转载】用ckeditor分页符结合正则表达式给文章分页
    ASP.NET MVC2中返回Json异常的解决办法
    CKEditor
    [转载].net下的生成静态页面并分页 .
  • 原文地址:https://www.cnblogs.com/zhber/p/4035894.html
Copyright © 2011-2022 走看看