题目:
http://poj.org/problem?id=1364
题意:
一个序列含有n个数,有q个限制条件,表示为区间和(s,s+n)> k 或是 区间和(s,s+n)< k. 判断是否能够得到这样一个序列。
思路:
Si 表示前i个数的和,则题目条件表示为 Si+n - Si < k : 建边(i,i+n, k-1); Si+n - Si > k: 建边(i+n,i,-k-1)。
此时建成的图不是连通图,则建立一个超级源点n+1使图连通,建边(n+1,i,0)。
若图存在负环,则不存在,否则存在这样一个序列。
AC.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 105;
int n, m;
int tol, head[maxn];
struct Edge{
int to, w, next;
}edge[maxn*100];
void addedge(int u, int v, int w)
{
edge[tol].to = v;
edge[tol].w = w;
edge[tol].next = head[u];
head[u] = tol++;
}
int vis[maxn], dis[maxn], ind[maxn];
bool spfa(int s)
{
int N;
N = n+2;
for(int i = 0; i <= n+1; ++i) {
vis[i] = 0;
ind[i] = 0;
dis[i] = inf;
}
queue<int> que;
vis[s] = 1;
dis[s] = 0;
que.push(s);
while(!que.empty()) {
int u = que.front(); que.pop();
vis[u] = 0;
for(int i = head[u]; ~i; i = edge[i].next) {
int v = edge[i].to, w = edge[i].w;
if(dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
if(!vis[v]) {
vis[v] = 1;
if(++ind[v] > N) return false;
que.push(v);
}
}
}
}
return true;
}
void init()
{
tol = 0;
memset(head, -1, sizeof(head));
}
int main()
{
//freopen("in", "r", stdin);
while(~scanf("%d", &n)) {
if(n == 0) break;
scanf("%d", &m);
init();
while(m--) {
int si, ni, k;
char ch[5];
scanf("%d %d %s %d", &si, &ni, ch, &k);
if(ch[0] == 'g') {
addedge(si+ni, si-1, -k-1);
}
else {
addedge(si-1, si+ni, k-1);
}
}
for(int i = 0; i <= n; ++i) {
addedge(n+1, i, 0);
}
if(spfa(n+1)) {
printf("lamentable kingdom\n");
}
else printf("successful conspiracy\n");
}
return 0;
}