您的位置:首页 > 其它

【POJ】1364 King

2015-07-29 19:48 281 查看
【解析】查分约束系统,最短路

[Problem]

S={a1,a2,a3,a4...ai...at},其中ai=a*si

现在给出多个不等式,使得ai+a[i+1]+a[i+2]+...+a[i+n]<ki或>ki

不等式这样描述:

给出四个参数i,n,s,d,i表示从序列的第i项开始,n表示序列长度为n,

当s="gt"时,表示A=ai+a[i+1]+...+a[i+n]>d,否则当s="lt"时,A<d。

询问是否有解。

[Analysis]

首先a*si可以不用管,谁知道a是多少呢,特殊值a=1就可以了。

由于是静态区间,考虑差分的思想,设tr[i]=∑a[j],1<=j<=i。

然后每一个约束条件都可以用差分的形式表示。

对于给定的i,n,s,d,

①当s="gt"时,

a[i]+a[i+1]+...+a[i+n]=tr[i+n]-tr[i-1]>d

∴tr[i+n]>d+tr[i-1]

∴tr[i-1]+(d+1)<=tr[i+n](式1)

建边(i-1,i+n,d+1)。

②当s="lt"

a[i]+...+a[i+n]=tr[i+n]-tr[i-1]<d

∴tr[i+n]+(1-d)<=tr[i-1]

建边(i+n,i-1,1-d)。(式2)

然后就求最长路看看有没有正权回路。(其实正负是差不多的,假如求负权回路就换一种建图方式)

至于为什么是正权回路而不是负权回路,这是为了满足每个约束条件,假如选了最短路,那么可能就会存在约束条件不满足。

用(式1)(式2)来理解。

接下来是求负权回路的方法。

求负权回路就用最短路的算法解决。

SPFA:设个数组vis,由于每个点不可能被松弛超过n次,所以当vis=n时就退出。

Bellman-Ford:O(n^3),稳定,代码短,具体就是枚举松弛次数,然后枚举两个点看看能不能松弛,最后再判断一次。

[Sum]

①回顾了查分约束系统的建图和求解。

②特别注意,用SPFA要n+1次的时候再判断不行。

#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;

const int N=160;
const int MAX=20000000;

int n,m;
struct G
{
int v,d,nxt;
}map
;
int tt,hd
;
int q
,h,t,used
,vis
,d
;

inline int read(void)
{
int s=0,f=1; char c=getchar();
for (;c<'0'||c>'9';c=getchar()) if (c=='-') f=-1;
for (;'0'<=c&&c<='9';c=getchar()) s=s*10+c-'0';
return s*f;
}

void ins(int u,int v,int d)
{
map[++tt].v=v;
map[tt].d=d;
map[tt].nxt=hd[u];
hd[u]=tt;
}

void build(void)
{
int x,y,d; char c;
tt=0; memset(hd,0,sizeof hd);

for (int i=1;i<=m;i++)
{
scanf("%d%d %ct %d",&x,&y,&c,&d);
if (c=='g')
ins(x+y,x-1,d+1);
else ins(x-1,x+y,1-d);
}

for (int i=0;i<=n;i++) ins(n+1,i,0); n++;
}

void spfa(void)
{
h=t=0;
memset(vis,0,sizeof vis);
memset(used,0,sizeof used);
for (int i=0;i<=n;i++) d[i]=-MAX;

d
=0,vis
=1,used
=1,q[t=1]=n;

int k;
for (;h^t;)
{
k=q[h=h%(n+1)+1];
for (int r=hd[k];r;r=map[r].nxt)
if (d[k]+map[r].d>d[map[r].v])
{
d[map[r].v]=d[k]+map[r].d;
vis[map[r].v]++;
if (vis[map[r].v]==n+1)
{
printf("successful conspiracy\n");
return;
}
if (!used[map[r].v])
{
used[map[r].v]=1;
q[t=t%(n+1)+1]=map[r].v;
}
}
used[k]=0;
}
printf("lamentable kingdom\n");
}

int main(void)
{
for (int cc=1;cc;cc++)
{
n=read();
if (!n) break;
m=read();
build();
spfa();
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: