题目链接:Click here~~
题意:
有 n 个石头,每个石头有一些能量,给出 m 个约束条件,条件是某区间 [a,b] 内的总能量在一个范围内。输出总能量最大的方案。
解题思路:
令 d[i] 表示区间 [0,i] 的总能量,则约束条件即可转变成 d[b] - d[a-1] >= A , d[b] - d[a-1] <= B。
还有两个隐含条件是 d[i] - d[i-1] >= -10000 , d[i] - d[i-1] <= 10000。
要求总能量最大,即要 d[n] 最大。根据不等式,转成最短路来求即可求得。
至于字典序最大的方案,由于此类差分模型求得的解 d[ ] 转化成其他解时需要同时加减一个数,才不影响之前的差分关系,所以差值不变。
故无所谓字典序最大方案,方案如果有的话就只有一种。
#include <queue>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
template<int N,int M>
struct Graph
{
int top;
struct Vertex{
int head;
}V[N];
struct Edge{
int v,next;
int w;
}E[M];
void init(){
memset(V,-1,sizeof(V));
top = 0;
}
void add_edge(int u,int v,int w){
E[top].v = v;
E[top].w = w;
E[top].next = V[u].head;
V[u].head = top++;
}
};
const int N = 1e3 + 5;
Graph<N,N*22> g;
int d[N],inqCnt[N];
bool inq[N];
bool spfa(int s,int n)
{
memset(inqCnt,0,sizeof(inqCnt));
memset(inq,false,sizeof(inq));
memset(d,63,sizeof(d));
queue<int> Q;
Q.push(s);
inq[s] = true;
d[s] = 0;
while(!Q.empty())
{
int u = Q.front();
for(int i=g.V[u].head;~i;i=g.E[i].next)
{
int v = g.E[i].v;
int w = g.E[i].w;
if(d[u] + w < d[v])
{
d[v] = d[u] + w;
if(!inq[v])
{
Q.push(v);
inq[v] = true;
if(++inqCnt[v] > n)
return false;
}
}
}
Q.pop();
inq[u] = false;
}
return true;
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
g.init();
while(m--)
{
int u,v,a,b;
scanf("%d%d%d%d",&u,&v,&a,&b);
g.add_edge(v,u-1,-a);
g.add_edge(u-1,v,b);
}
for(int i=1;i<=n;i++)
{
g.add_edge(i-1,i,10000);
g.add_edge(i,i-1,10000);
}
if(spfa(0,n+1))
for(int i=1;i<=n;i++)
printf("%d%c",d[i]-d[i-1],i==n?'\n':' ');
else
puts("The spacecraft is broken!");
}
return 0;
}