首页 > 代码库 > shortpath3159差分约束

shortpath3159差分约束

题目意思: flymouse是幼稚园班上的班长,一天老师给小朋友们买了一堆的糖果,由flymouse来分发,在班上,flymousesnoopy是死对头,两人势如水火,不能相容,因此fly希望自己分得的糖果数尽量多于snoopy,而对于其他小朋友而言,则只希望自己得到的糖果不少于班上某某其他人就行了。 比如A小朋友强烈希望自己的糖果数不能少于B小朋友m个,即B- A<=mAB分别为 AB小朋友的分得的糖果数。因此根据题意,可以列出如下的不等式:         Sbi-Sai<=ci(1=<i<=n)                   最终要使得Sn-S1最大; 其实就是一个差分约束系统。 首先把ai,bi的边权值赋值为cisa-sb<=ci,表示SA离源点的最短路径和SB离源点的最短路径只差肯定小于第三边。

s[0]=0把所有节点的值都换算成最短路径权值后,那么s[a]<=s[b]+w(a,b)。也就满足了所有要求的条件,

 

对于目标函数Sn-S1,起始时,S1=0SN=MAX,因为要满足各个限制条件(即需要松弛),因此在松弛过程中,Sn逐渐减小,直到满足所有限制条件,于是得到了满足所有条件的最大Sn

 

N个人份糖果,其中含有约束条件,即对于a,b,c有 b-a<=c,看到这个不等式马上感觉到要用最短路解决了,问Sn-S1的最大值是多少,查分约束题目,

 

邻接表与邻接矩阵相比,前者在搜索相邻节点时,花费时间更少。

这里对输入建立链表的过程有点复杂,比如有如下输入

u v len

1 2 5,

1 3 7 

1 5 8

表示1节点到2节点有一个5的边;1节点到3节点有一个7权值的边。。。

考虑ADD函数的各个步骤:

Node[i]表示第i条边

代码:

 Cou表示当前节点

node[cou].to = v;

node[cou].len = len;

node[cou].next = kid[u];//覆盖KID[U]之前,保存前一个KID[U]

kid[u] = &node[cou++];//KID[U]表示起点U指向的下一个节点。

 

Node[0].to=2

Node[0].len=5

Node[0].next=kid[1]

Kid[1]->node[0]

 

当然这里kid可以用一维数组来表示地址,不用结构体的指针。

Node[1].to=3

Node[1].len=7

Node[1].next=kid[1]->node[0]

Kid[1]->node[1]

 

Node[2].to=5

Node[2].len=8

Node[2].next=kid[1]->node[1]

Kid[1]->node[2]

 

当考察1节点的各个相邻节点时,首先从kid[1]开始,得到node[2](第2号边,不是第2个节点),即1,5这条边。之后访问node[2]next,得到node[1],再访问node[1]next得到node[0]

 

#include <cstdio>

#include <cstdlib>

#include <iostream>

#include <string.h>

#include <queue>

#include <limits.h>

#define MAX 30010

using namespace std;

typedef struct CANDY{

int to,len;

int num; 

CANDY *next;

}CANDDY;

CANDY *kid[MAX],node[MAX*10];

typedef struct DIS{

int len,num;

}DIS;

int cou,n;

void init()

{

memset(kid,‘/0‘,sizeof(kid));

memset(node,‘/0‘,sizeof(node));

cou = 0;

}

bool operator<(DIS a,DIS b)

{

return a.len > b.len;

}

priority_queue <DIS> Q;

int Dijkstra()

{

while( !Q.empty() )

Q.pop(); 

int i,k,used[MAX],now,len,to;

DIS dis[MAX],tmp;

CANDY *head;

memset(used,0,sizeof(used));

for(i=1; i<=n; i++)

{

dis[i].num = i;

dis[i].len = INT_MAX;

}

dis[1].len = 0;

dis[1].num = 1;//num表示序号,len相当于DIJ算法里面的d[]

Q.push(dis[1]);

while( !Q.empty() )

{

tmp = Q.top();

Q.pop();

now = tmp.num;

if( used[now] == 1 )

continue;

used[now] = 1;

head = kid[now];

while( head != NULL )

{

len = head->len;

to = head->to;

if( dis[to].len > dis[now].len + len )

{

dis[to].len = dis[now].len + len;

Q.push(dis[to]);

}

head = head->next;

}

}

return dis[n].len;

}

void Add(int u,int v,int len)

{

node[cou].to = v;

node[cou].len = len;

node[cou].next = kid[u];

kid[u] = &node[cou++];

}

int main()

{

int from,to,len,m,ans,i;

while( scanf("%d%d",&n,&m) != EOF )

{

init();

while( m-- )

{

  add....

  }

ans = Dijkstra();

printf("%d/n",ans);

}

return 0;

}

 

 

本题用spfa+stack(队列不行,应该特殊的数据原因造成的)也可以:、

 

 

#include<iostream>

using namespace std;

const int MAX=30005;

const int inf=1<<30;

struct node

{

int v,w,next;

}g[MAX*10];

int dis[MAX],adj[MAX],s[MAX],vis[MAX];

int n,m,e;

void add(int u,int v,int c)

{

g[e].v=v; g[e].w=c; g[e].next=adj[u]; adj[u]=e++;

}

void spfa()

{

int top=0,i,u,v;

for(i=1;i<=n;i++)

dis[i]=inf;

dis[1]=0;

memset(vis,0,sizeof(vis));

s[++top]=1;//栈只需要用一个对标即可,到0了说明为空,0位置不用。

vis[1]=1;

while(top)

{

u=s[top--];

//cout<<u<<endl;

vis[u]=0;

for(i=adj[u];i!=-1;i=g[i].next)

{

v=g[i].v;

if(dis[v]>dis[u]+g[i].w)

{

dis[v]=dis[u]+g[i].w;

if(!vis[v])

{

s[++top]=v;

vis[v]=1;

}

}

}

}

}

int main()

{

int a,b,c;

memset(adj,-1,sizeof(adj));

e=0;

scanf("%d%d",&n,&m);

while(m--)

{

scanf("%d%d%d",&a,&b,&c);

add(a,b,c);

}

spfa();

cout<<dis[n]<<endl;

return 0;

}