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 i, xi 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, xRi−xLi=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
- 1≤N≤100 000
- 0≤M≤200 000
- 1≤Li,Ri≤N (1≤i≤M)
- 0≤Di≤10 000 (1≤i≤M)
- Li≠Ri (1≤i≤M)
- If i≠j, 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
3 3 1 2 1 2 3 1 1 3 2
Sample Output 1
Yes
Some possible sets of values (x1,x2,x3) are (0,1,2) and (101,102,103).
Sample Input 2
3 3 1 2 1 2 3 1 1 3 5
Sample Output 2
No
If the first two pieces of information are correct, x3−x1=2 holds, which is contradictory to the last piece of information.
Sample Input 3
4 3 2 1 1 2 3 5 3 4 2
Sample Output 3
Yes
Sample Input 4
10 3 8 7 100 7 9 100 9 8 100
Sample Output 4
No
Sample Input 5
100 0
Sample Output 5
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名,這一次第四題應該比上一次簡單些,但是還是沒做出來。學到的東西需要融會貫通。。