题目描述
造一栋大楼是一项艰巨的工程,它是有n个子任务构成的,给它们分别编号1,2,3,….,n(5<=n<=1000).由于对一些任务的起始条件有着严格地限制,所以每个任务的起始时间T1,T2,T3….,Tn并不是很容易确定的(但这些起始时间都是非负整数,因为它们必须在整个工程开始后启动).例如:挖掘完成后,紧接着就要打地基;但是混泥土浇筑完成后,却要等待一段时间再去掉模板.
这种要求就可以用m(5<=m<=5000)个不等式表示,不等式形如ti-tj<=B代表i和j的起始时间必须满足的条件.每个不等式的右边都是一个常数B,这些常数可能不相同,但是它们都在区间(-100,100)内.
你的任务就是写一个程序,当给定像上面那样的不等式后,找出一种可能的起始时间序列T1,T2,T3….,Tn,或者判断问题无解.对于有解的情况,要使最早进行的哪个任务和整个工程的起始时间,也就是说,T1,T2,T3….,Tn中至少有一个0.
输入格式
第一行是用空格分开的两个正整数N和M,下面的M行每行有三个用空格分开的整数i,j,B对应着不等式ti-tj<=B.
输出格式
如果有可行的方案,那么输出N行,每行都有一个非负整数且至少有一个0,按照顺序表示每个任务的起始时间.如果没有可行的方案,就输出信息”NO SOLUTION”.
样例数据
样例输入
5 8
1 2 0
1 5 -1
2 5 1
3 1 5
4 1 4
4 3 -1
5 3 -3
5 4 -3
样例输出
0
2
5
4
1
说明
bsoj无special judge,md坑爹,必须手动建虚点0连接所有点,否则wrong answer
题目分析
裸差分约束,写了个不太完美的模板
源代码
#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
inline const int Get_Int() {
int num=0,bj=1;
char x=getchar();
while(x<'0'||x>'9') {
if(x=='-')bj=-1;
x=getchar();
}
while(x>='0'&&x<='9') {
num=num*10+x-'0';
x=getchar();
}
return num*bj;
}
const int maxn=20005;
struct Edge {
int from,to,dist;
} E[50005];
struct Difference_Constraints { //差分约束系统
int n,m;
vector<Edge>edges;
vector<int>G[maxn];
bool inque[maxn];
int dist[maxn],used[maxn];
int ans[maxn]; //ans表示不等式组答案
void init(int n) {
this->n=n;
edges.clear();
for(int i=1; i<=n; i++)G[i].clear();
}
void AddEdge(int from,int to,int dist) {
edges.push_back((Edge) {
from,to,dist
});
m=edges.size();
G[from].push_back(m-1);
}
void insert(int x,int y,int v,bool flag) { //x-y<=v (flag=0),x-y>=v (flag=1)
if(flag==0)AddEdge(y,x,v);
if(flag==1)AddEdge(y,x,-v);
}
bool spfa(int s) {
for(int i=1; i<=n; i++)dist[i]=0x7fffffff/2;
memset(inque,0,sizeof(inque));
deque<int>Q;
Q.push_back(s);
dist[s]=0;
inque[s]=1;
used[s]++;
while(!Q.empty()) {
int Now=Q.front();
Q.pop_front();
inque[Now]=0;
for(int i=0; i<G[Now].size(); i++) {
Edge& e=edges[G[Now][i]];
int Next=e.to;
if(dist[Next]>dist[Now]+e.dist) {
dist[Next]=dist[Now]+e.dist;
if(!inque[Next]) {
used[Next]++;
if(used[Next]==edges.size())return false; //负权回环
if(!Q.empty()&&dist[Next]<dist[Q.front()])Q.push_front(Next); //SLF优化
else Q.push_back(Next);
inque[Next]=1;
}
}
}
}
return true;
}
bool main(int Start,bool flag) { //求出正整数解
if(spfa(Start)==0)return false;
int Min=0x7fffffff/2;
if(flag==1) { //最长路
for(int i=1; i<=n; i++)dist[i]*=-1;
}
for(int i=1; i<=n; i++)Min=min(Min,dist[i]); //转为正数
for(int i=1; i<=n; i++)ans[i]=dist[i]-Min;
return true;
}
void Output() {
for(int i=1; i<=n; i++)printf("%d\n",ans[i]);
}
};
Difference_Constraints dc; //全程小于符
int n,m;
int main() {
n=Get_Int();
m=Get_Int();
dc.init(n);
int Start=0; //由于本题没有spj因此必须建虚点0否则会wa
for(int i=1; i<=n; i++)dc.insert(i,Start,0,0);
for(int i=1; i<=m; i++) {
int x=Get_Int(),y=Get_Int(),v=Get_Int();
dc.insert(x,y,v,0);
}
if(dc.main(Start,0)==0) {
puts("NO SOLUTION");
return 0;
}
dc.Output();
return 0;
}