首页 > 代码库 > shortpath3159差分约束
shortpath3159差分约束
题目意思: flymouse是幼稚园班上的班长,一天老师给小朋友们买了一堆的糖果,由flymouse来分发,在班上,flymouse和snoopy是死对头,两人势如水火,不能相容,因此fly希望自己分得的糖果数尽量多于snoopy,而对于其他小朋友而言,则只希望自己得到的糖果不少于班上某某其他人就行了。 比如A小朋友强烈希望自己的糖果数不能少于B小朋友m个,即B- A<=m,A,B分别为 A、B小朋友的分得的糖果数。因此根据题意,可以列出如下的不等式: Sbi-Sai<=ci(1=<i<=n) 最终要使得Sn-S1最大; 其实就是一个差分约束系统。 首先把ai,bi的边权值赋值为ci,sa-sb<=ci,表示SA离源点的最短路径和SB离源点的最短路径只差肯定小于第三边。
s[0]=0把所有节点的值都换算成最短路径权值后,那么s[a]<=s[b]+w(a,b)。也就满足了所有要求的条件,
对于目标函数Sn-S1,起始时,S1=0,SN=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;
}