题目:http://poj.org/problem?id=1364
题意:就是简单的差分约束模型。
分析:首先我们必须知道,如果图中存在负权回路,那么差分约束没有可行解。而存在负权回路的条件是:图中某条边的松
弛操作的次数超过n次。对于Bellman_Ford,我们很容易解。如下:
#include
#include
#include
using namespace std;
const int N = 105;
const int INF = 1<<29;
struct Edge
{
int s,t;
int w;
};
Edge edge[N*N];
int dist[N];
int cnt,n,m;
void add(int u,int v,int w)
{
edge[cnt].s = u;
edge[cnt].t = v;
edge[cnt].w = w;
cnt++;
}
void Relax(int s,int t,int w)
{
if(dist[t] > dist[s] + w)
dist[t] = dist[s] + w;
}
bool Bellman_Ford(int s)
{
for(int i=0; i dist[edge[i].s] + edge[i].w)
return true;
return false;
}
int main()
{
char str[5];
while(cin>>n)
{
if(n == 0) break;
cin>>m;
cnt = 0;
while(m--)
{
int a,b,c;
cin>>a>>b>>str>>c;
if(str[0]=='l')
add(a-1,a+b,c-1);
else
add(a+b,a-1,-c-1);
}
if(Bellman_Ford(0)) cout<<"successful conspiracy"<
对于判断负权回路问题,我们还是用Spfa算法最好,时间复杂度比较低。实际上Spfa跟Bellman_Ford算法差不多,Spfa
是Bellman_Ford算法的一种队列实现,大大减少了不必要的冗余计算。
下面是Spfa判断负权回路的方法:
#include
#include
#include
#include
using namespace std;
const int N = 105;
const int INF = 1<<29;
struct Edge
{
int to;
int w;
int next;
};
Edge edge[N*N];
bool vis[N];
int head[N],time[N],dist[N];
int n,m,cnt;
queue Q;
void add(int u,int v,int w)
{
edge[cnt].to = v;
edge[cnt].w = w;
edge[cnt].next = head[u];
head[u] = cnt++;
}
void Init()
{
cnt = 0;
memset(head,-1,sizeof(head));
memset(vis,0,sizeof(vis));
memset(time,0,sizeof(time));
}
bool Spfa(int s)
{
for(int i=0; i<=n+1; i++)
dist[i] = -INF;
dist[s] = 0;
time[s] = 1;
vis[s] = 1;
while(!Q.empty()) Q.pop();
Q.push(s);
while(!Q.empty())
{
int u =Q.front();
vis[u] = 0;
Q.pop();
for(int i=head[u]; ~i; i=edge[i].next)
{
int v = edge[i].to;
int w = edge[i].w;
if(dist[v] < dist[u] + w)
{
dist[v] = dist[u] + w;
if(!vis[v])
{
vis[v] = 1;
Q.push(v);
time[v]++;
if(time[v] > n)
return false;
}
}
}
}
return true;
}
int main()
{
char str[5];
while(cin>>n)
{
Init();
if(n == 0) break;
cin>>m;
for(int i=0; i>a>>b>>str>>c;
if(str[0] == 'g')
add(a + b + 1,a,c + 1);
else
add(a,a + b + 1,1 - c);
}
int s = 0;
if(Spfa(s)) cout<<"lamentable kingdom"<
当然,对于Spfa判负环,实际上还有优化:就是把判断单个点的入队次数大于n改为:如果总的点入队次数大于所有点两倍
时有负环,或者单个点的入队次数大于sqrt(点数)有负环。这样时间复杂度就降了很多了。
经典题目:
题目:http://acm.hdu.edu.cn/showproblem.php?pid=3666
分析:本题要先取对数,然后转化为差分约束模型,再判断有没有解就可以了。注意这里时间限制紧,判负环要优化。
题目:http://poj.org/problem?id=3259
分析:典型的差分约束题目,直接判断负环就行,这里数据不大,可以直接就用单个点入队次数是否超过n判断就可以了。
题目:http://acm.hdu.edu.cn/showproblem.php?pid=1384
题意:在每个区间上至少选择个元素,构成一个集合S,使得集合S中的元素最少。
分析:设表示在区间上选择的元素的个数。那么有:,并且很明显还有:
,然后我们根据这两个不等式建图,然后就转化为最长路径问题。
#include
#include
#include
#include
using namespace std;
const int N = 50005;
const int INF = 1<<30;
struct Edge
{
int to;
int w;
int next;
};
Edge edge[4*N];
bool vis[N];
int head[N],dist[N];
int cnt,s,t;
queue Q;
void Init()
{
cnt = 0;
memset(vis,0,sizeof(vis));
memset(head,-1,sizeof(head));
}
void add(int u,int v,int w)
{
edge[cnt].to = v;
edge[cnt].w = w;
edge[cnt].next = head[u];
head[u] = cnt++;
}
void Spfa(int s)
{
for(int i=0; i t) t = v + 1;
add(u,v+1,w);
}
for(int i=s; i<=t; i++)
{
add(i,i-1,-1);
add(i-1,i,0);
}
Spfa(s);
printf("%d\n",dist[t]);
}
return 0;
}