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; 
}


分数阶微分方程是一类比常见的线性微分方程更为复杂的方程,其被广泛应用于物理、生物、金融等领域。本文将介绍如何使用MATLAB编写解决分数阶微分方程的代码。 首先,将分数阶微分方程转化为常微分方程。这可以通过采用Caputo定义,或者Grünwald-Letnikov定义加权平均来实现。在这里,我们采用Caputo定义将分数阶微分方程转化为常微分方程。 接下来,我们可以使用MATLAB中的ode45函数解决常微分方程。ode45是一种常用的解决常微分方程的函数,它可以在一定时间范围内对微分方程进行数值解。 代码演示: % 定义分数阶微分方程 y(t) function dydt = fractional_deriv(t,y,alpha) dydt = zeros(1,1); dydt(1) = Caputo_derivative(y,alpha); % 定义Caputo导数 function result = Caputo_derivative(y,alpha) syms t p; f = laplace(y,t,p); result = real(ilaplace((p^alpha)*f,p,t)); % 定义初始值 y0 = 0.5; % 定义时间范围 tspan = [0 10]; % 定义分数阶参数 alpha = 0.5; % 使用ode45函数解决微分方程 [t,y] = ode45(@(t,y)fractional_deriv(t,y,alpha),tspan,y0); % 打印结果 plot(t,y); 在以上代码示例中,我们定义了分数阶微分方程和Caputo导数,然后使用ode45函数来解决得到结果。最后,我们绘制了图形以分析解决方案的有效性。 在MATLAB中解决分数阶微分方程并不困难,只要有一定的编程基础和问题领域的背景知识,就可以轻松地解决分数阶微分方程问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值