2018.1.29【 AtCoder Beginner Contest 087-D 】解题报告(TLE)(STL,队列)

6 篇文章 0 订阅

D - People on a Line


Time limit : 2sec / Memory limit : 256MB

Score : 400 points

Problem Statement

There are N people standing on the x-axis. Let the coordinate of Person i be xi. For every ixi is an integer between 0 and 109 (inclusive). It is possible that more than one person is standing at the same coordinate.

You will given M pieces of information regarding the positions of these people. The i-th piece of information has the form (Li,Ri,Di). This means that Person Ri is to the right of Person Li by Di units of distance, that is, xRixLi=Di holds.

It turns out that some of these M pieces of information may be incorrect. Determine if there exists a set of values (x1,x2,…,xN) that is consistent with the given pieces of information.

Constraints

  • 1N100 000
  • 0M200 000
  • 1Li,RiN (1iM)
  • 0Di10 000 (1iM)
  • LiRi (1iM)
  • If ij, then (Li,Ri)(Lj,Rj) and (Li,Ri)(Rj,Lj).
  • Di are integers.

Input

Input is given from Standard Input in the following format:

N M
L1 R1 D1
L2 R2 D2
:
LM RM DM

Output

If there exists a set of values (x1,x2,…,xN) that is consistent with all given pieces of information, print Yes; if it does not exist, print No.


Sample Input 1

Copy
3 3
1 2 1
2 3 1
1 3 2

Sample Output 1

Copy
Yes

Some possible sets of values (x1,x2,x3) are (0,1,2) and (101,102,103).


Sample Input 2

Copy
3 3
1 2 1
2 3 1
1 3 5

Sample Output 2

Copy
No

If the first two pieces of information are correct, x3x1=2 holds, which is contradictory to the last piece of information.


Sample Input 3

Copy
4 3
2 1 1
2 3 5
3 4 2

Sample Output 3

Copy
Yes

Sample Input 4

Copy
10 3
8 7 100
7 9 100
9 8 100

Sample Output 4

Copy
No

Sample Input 5

Copy
100 0

Sample Output 5

Copy
Yes

【题目大意】

有N点在一条数轴上,坐标未X1,X2...XnM条信息,每条信息给出Li,Ri,Di,表示Xri-Xli=Di。判断这N个点能否全部满足着M条信息不冲突。

【解题思路】

1.直接利用队列。不断遍历直至队列为空输出Yes,或者出现矛盾输出No。

区分关联点信息对和非关联点信息,对于第i条信息,若Li和Ri均提到>=2次,则该信息未关联点信息,也即与其他信息共同决定是否正确。反之则为非关联点信息,举个栗子,如果Li,Ri只提到一次,那么显而易见由于点的坐标值可以重复,那么放到任意位置满足两点之间的条件即可。另若其中Li或Ri提到两次,另一者提到一次,那么只需要满足其他信息合理,再让只提到一次的点根据两点间距离调整满足即可。

关联点的建立是因为TLE了。。不过该了以后依旧,还在想办法。

另外注意每次遍历队列时,不是新一轮的第一个点对就可以重新设定原点(可能本轮后面的值有关联性导致下一轮第一个点也受影响)在开始由于没有注意到这一点一直WA,找了好久。目前解决办法时直到遍历队列一轮弹出值为0才可以重新从设点对原点,貌似有点浪费时间。。。

2.好像可以用DFS和BFS解,比赛时没来得及想,有待尝试。。

【解题代码】(TLE代码)

#include <queue>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>

using namespace std;
const int maxn=200010; 
const int mmin=-200000000;
int N,M;
int X[maxn],Li[maxn],Ri[maxn],Di[maxn]; 
struct message
{
	int l;
	int r;
	int d;
	int circle;
};
message a[maxn];
int vis[maxn];
queue <message> q;
int main()
{
//		freopen("in.txt","r",stdin);
	while(~scanf("%d%d",&N,&M))
	{
		memset(vis,0,sizeof(vis));
		while(!q.empty()) q.pop();
		for(int i=0;i<maxn;i++)
			X[i]=mmin;
		for(int i=0;i<M;i++)
		{
			scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].d);
			a[i].circle=1;
			vis[a[i].l]++;vis[a[i].r]++;//记录点的关联度, 
		}
		for(int i=0;i<M;i++)
		{
			if(vis[a[i].l]>=2&&vis[a[i].r]>=2)//关联点入队, 
			{
				q.push(a[i]);
//				printf("push l=%d r=%d d=%d  circle=%d\n",a[i].l,a[i].r,a[i].d,a[i].circle);
			}
		}
		int flag=0;
//		for(int i=0;i<M;i++)
//			printf("Xi=%d\n",X[i]);
		int nowcircle=0;
		int count=0;//记录一轮筛出的个数 
		while(!q.empty())
		{
			message now=q.front();
			q.pop(); 
			int li=now.l,ri=now.r,di=now.d,ci=now.circle;
//均未出现该关系点,初始化
//均未初始化
//均初始化 
			if(ri>N||li>N)
			{
				flag=1;
				break;
			}
			else if(X[ri]!=mmin&&X[li]!=mmin)
			{
				count++;
//				printf("Xl[%d]=%d   Xr[%d]=%d   X %d\n",li,X[li],ri,X[ri],X[2]);
				int tempXi=X[li]+di;
				if(tempXi!=X[ri])
				{
					flag=1;
//					printf("argue l=%d r=%d d=%d  circle=%d\n",now.l,now.r,now.d,now.circle);
					break;
				}
			}
			else if(X[ri]!=mmin) 
			{
				count++;
				X[li]=X[ri]-di;
//				printf("set left l=%d r=%d d=%d  circle=%d\n",now.l,now.r,now.d,now.circle);
			}
			else if(X[li]!=mmin) 
			{
				count++;
				X[ri]=X[li]+di;
//				printf("set right l=%d r=%d d=%d  circle=%d\n",now.l,now.r,now.d,now.circle);
			}
			else if(nowcircle!=ci)
			{
				if(!count)
				{
					nowcircle=ci;
					count=1;
					X[li]=0;
					X[ri]=X[li]+di;
//					printf("set zero l=%d r=%d d=%d  circle=%d\n",now.l,now.r,now.d,now.circle);	
				}
				else
				{
					nowcircle=ci;
					count=0;
					message next;
					next.l=li;
					next.r=ri;
					next.d=di;
					next.circle=ci+1;
					q.push(next);
//					printf("roll back l=%d r=%d d=%d  circle=%d\n",next.l,next.r,next.d,next.circle);
				}
			}
			else
			{
				message next;
				next.l=li;
				next.r=ri;
				next.d=di;
				next.circle=ci+1;
				q.push(next);
//				printf("roll back l=%d r=%d d=%d  circle=%d\n",next.l,next.r,next.d,next.circle);
			}
		}
		if(flag) printf("No\n");
		else printf("Yes\n");

		
	}
}

【收获与反思】

哎,速度不够快,前三题是精准了些,但是太慢了啊。出来1题400名,2题300名,3题200名,这一次第四题应该比上一次简单些,但是还是没做出来。学到的东西需要融会贯通。。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值