POJ 1364 King 【差分约束 + 判环模型】

传送门
/ 题意:
n个数的一个序列,m个约束,
si, ni, oi, ki, 代表了序列中第si个数到第si+ni个数的和大于或小于ki, oi = gt = 大于, oi = lt = 小于
问是否存在相悖的约束

// 思路: 很明显的不等式, 再看问题即可知道就是差分约束.
约束已经很明显了设sum[i]为前i个数的和,那么就可以得到约束:si, ni, gt, ki , 因为是小于, 然后又是在整数域, 所以我们做等于的情况.
sum[0] = 0
oi为gt时:sum[si+ni] - sum[si-1] >= ki+1
oi为lt时:sum[si+ni] - sum[si-1] <= ki-1
然后就是建图, 求1 - n 的最短路, 如果不满足国王的逻辑, 则这幅图中一定存在负环.
注: 因为我跑的最短路, 所以就是直接判有无负环, 所以dis的初始值都要是inf, 还有就是有可能建的这幅图不连通, 所以判不到负环去, 所以要把所有的点都推进队列去找. 只要有一个有负环就不满足国王的逻辑. 因为推进了所有的点, 所以所有的距离都是inf, 只要有负环的话始终会进队列的, 因为我们加的里面有负权边呀!!!

// 因为我是以 <= 为准, 所以我们跑最短路, 判负环, 当然以 >= 为准也行, 这是就是跑最长路, 判正环, 总之一定要根据你定的那个标准为准.

AC Code

const int maxn=1e5+5;
const int inf = 0x3f3f3f3f; //用这个可以直接mem
int cas = 1;
int n,m;
int head[maxn], cnt, dis[maxn];
bool vis[maxn];
int times[maxn];
struct node
{
    int to,next,w;
}e[maxn<<1];
void add(int u, int v, int w)
{
    e[cnt] = (node){v,head[u],w};
    head[u] = cnt++;
}
void init() {
    cnt = 0 ;
    Fill(head, -1);
}
bool spfa(int st,int ed)
{
    Fill(dis, inf); Fill(vis, 0);
    queue<int >q; Fill(times, 0);
    for(int i=0;i<=n;i++){
        q.push(i);     //每个点都要进去.
        vis[i] = true;
        times[i]++;
    }
    q.push(st);  // dis距离全是inf.
    while(!q.empty()){
        int u = q.front();
        q.pop();
        vis[u] = false;
        for(int i = head[u]; ~i ;i = e[i].next){
            int to = e[i].to;
            //因为我定的是小于, 所以我跑最短路.由于每个点都在队列,所以dis的值都是inf
            // 有负权边的话始终会进去, 有负环的话始终会多次入队,
            if(dis[to] > dis[u] + e[i].w){
                dis[to] = dis[u] + e[i].w;
                if(times[to] > n)
                    return false;
                else if(!vis[to]){
                    times[to]++;
                    vis[to] = true;
                    q.push(to);
                }
            }
        }
    }
    return true;
}

void solve()
{
    while(~scanf("%d",&n) && n){
        scanf("%d",&m);
        init();
        for(int i=1;i<=m;i++){
            int u, v, w; string s;
            cin >> u >> v >> s >> w;
            if(s == "gt"){   //gt代表大于.
                add(u+v, u-1, -(w+1)); //而路肯定是要取等于的.所以应该取>=
            }
            else add(u-1, u+v, w-1); //lt代表小于.
        }
        if(spfa(1,n)) printf("lamentable kingdom\n");
        else printf("successful conspiracy\n");
    }
}

你可能感兴趣的:(差分约束系统)