1. 程式人生 > >HDU 2017中國大學生程式設計競賽-總決賽 Subway Chasing [差分約束]

HDU 2017中國大學生程式設計競賽-總決賽 Subway Chasing [差分約束]

題意:我與朋友要從1走到n,朋友比我先x分鐘走,然後給出m個事件,每個事件給出我的與朋友的位置,求符合這些事件的相鄰的點的距離。

題解:可以看出每個事件可以給出2種情況:

①a==b&&c==d 那麼我們能得到差分條件:c-a<=x  a-c<=-x

②a-d<=-(x+1)   c-b<=x-1

然後約束一下相鄰點的距離要大於1  

for(int i=2;i<=n;i++)
    	AddEdges(i-1,i,-1);

跑差分約束得到的Dist,相鄰Dist相減就是答案。

AC程式碼:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#define INF 0x7fffffff
using namespace std;
const int MAXN = 2005;
const int MAXM = 30030;
struct EdgeNode
{
    int to;
    int w;
    int next;
}Edges[MAXM];
int Head[MAXN],Dist[MAXN],vis[MAXN],outque[MAXN],id;
void AddEdges(int u,int v,int w)
{
    Edges[id].to = v;
    Edges[id].w = w;
    Edges[id].next = Head[u];
    Head[u] = id++;
}
void SPFA(int s,int N)
{
    int ans = 0;
    memset(vis,0,sizeof(vis));
    memset(outque,0,sizeof(outque));
    for(int i = 1; i <= N; ++i)
        Dist[i] = INF;
    Dist[s] = 0;
    vis[s] = 1;
    queue<int> Q;
    Q.push(s);
    while( !Q.empty() )
    {
        int u = Q.front();
        Q.pop();
        vis[u] = 0;
        outque[u]++;
        if(outque[u] > N+1) //如果出隊次數大於N,則說明出現負環
        {
            ans = -1;
            break;
        }
        for(int i = Head[u]; i != -1; i = Edges[i].next)
        {
            int temp = Dist[u] + Edges[i].w;
            if(temp < Dist[Edges[i].to])
            {
                Dist[Edges[i].to] = temp;
                if( !vis[Edges[i].to])
                {
                    vis[Edges[i].to] = 1;
                    Q.push(Edges[i].to);
                }
            }
        }
    }
    if(ans == -1)   //出現負權迴路,不存在可行解
        printf("IMPOSSIBLE\n");
    else 
    {
    	for(int i=2;i<=N;i++)
	    	printf(" %d",Dist[i-1]-Dist[i]);
   		printf("\n");
    }
}

int main()
{
    int T;
    scanf("%d",&T);
    int cas=1;
    while(T--)
    {
        memset(Head,-1,sizeof(Head));
        id = 0;
    	int n,m,x;
    	scanf("%d%d%d",&n,&m,&x);
    	for(int i=2;i<=n;i++)
    		AddEdges(i-1,i,-1);
    	for(int i=0;i<m;i++)
    	{
    		int a,b,c,d;
			scanf("%d%d%d%d",&a,&b,&c,&d);
			if(a==b&&c==d)
			{
				AddEdges(c,a,x);
				AddEdges(a,c,-x);
			}
			else 
			{
				AddEdges(a,d,-(x+1));
				AddEdges(c,b,x-1);
			}
		} 
		printf("Case #%d:",cas++);
        SPFA(1,n);
    }
    return 0;
}