【BZOJ】【P1202】【狡猾的商人】【题解】【线性规划=>差分约束】

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1202

很显然这道题就是给定n个数,m个区间和,问是否合法

线性规划显然,x_i表示每个数的值,约束就是区间和,由于可能出现负数,所以每一个都要加一个叫较大的正值,用线性规划的初始化判断可行性就好了,

不过这样会T……只有60分,T的原因在于建立线性规划的式子太费时了

于是优化成前缀和的形式,如果[l,r]的和为v,那么x_r-x_{l-1}=v,拿来数据一测,7s A了,交在bzoj上却T了……找了台linux自测,A了……然后就各种蛋疼……

忽然想到改成前缀和的形式不就差分约束吗……可行性判负环不就好了……………………

60分线性规划:

#include<bits/stdc++.h>
using namespace std;
const int maxn=2100;
const int maxm=110;
const double eps=1e-6;
double a[maxn][maxm];
int n,m;
int dcmp(double x){
	if(fabs(x)<eps)return 0;
	return x>0?1:-1;
}
double simplex(bool f);
void pivot(int l,int e,bool f){
	for(int i=0;i<=m+f;i++){
		if(i==e)continue;
		a[l][i]/=a[l][e];
	}a[l][e]=1/a[l][e];
	for(int i=0;i<=n+f;i++){
		if(i==l)continue;
		for(int j=0;j<=m+f;j++){
			if(j==e)continue;
			a[i][j]-=a[i][e]*a[l][j];
		}a[i][e]*=-a[l][e];
	}
}
bool init(){
	int pos=-1;
	double minn=1e300;
	for(int i=1;i<=n;i++)
	if(dcmp(minn-a[i][0])==1)minn=a[i][0],pos=i;
	if(dcmp(minn)>=0)return 1;
	for(int i=0;i<=m;i++)swap(a[0][i],a[n+1][i]);
	for(int i=0;i<=n;i++)a[i][m+1]=-1;
	pivot(pos,m+1,1);
	if(!dcmp(simplex(1))){
		for(int i=1;i<=m+1;i++)if(!dcmp(a[0][i]+1)){pos=i;break;}
		for(int i=0;i<=m+1;i++)swap(a[0][i],a[n+1][i]);
		for(int i=0;i<=n+1;i++)swap(a[i][pos],a[i][m+1]);
	}else return 0;
	return 1;
}
double simplex(bool f){
	for(;;){
		int pos=-1,l,e;
		double minn=0;
		for(int i=1;i<=m+f;i++)
		if(dcmp(a[0][i]-minn)==1)minn=a[0][i],pos=i;
		if(!~pos)return -a[0][0];
		e=pos;pos=-1;minn=1e300;
		for(int i=1;i<=n;i++)
		if(dcmp(a[i][e])==1&&dcmp(a[i][0]/a[i][e]-minn)==-1)
		minn=a[i][0]/a[i][e],pos=i;
		if(!~pos){
			printf("INF!!\n");
			return 1e300;
		}l=pos;
		pivot(l,e,f);
	}
}
int T;
int main(){
//	freopen("123.txt","w",stdout);
	scanf("%d",&T);
	while(T--){
		scanf("%d%d",&m,&n);
		int now=0;
		int l,r,v;
		memset(a,0,sizeof(a));
		for(int j=1;j<=n;j++){
			scanf("%d%d%d",&l,&r,&v);
			for(int i=l;i<=r;i++){
				a[0][i]=1;
				a[now+1][i]=1;
				a[now+2][i]=-1;
			}
			a[now+1][0]=v+(r-l+1)*5e2;
			a[now+2][0]=-v-(r-l+1)*5e2;
			now+=2;
		}
		n+=n;
		if(init())puts("true");
		else puts("false");
	}	
	return 0;
}

7s+ 线性规划:

#include<bits/stdc++.h>
using namespace std;
const int maxn=3011;
const int maxm=101;
const double eps=1e-2;
double a[maxn][maxm];
int n,m;
int dcmp(double x){
	if(fabs(x)<eps)return 0;
	return x>0?1:-1;
}
double simplex(bool f);
void pivot(int l,int e,bool f){
	for(int i=0;i<=m+f;i++){
		if(i==e)continue;
		a[l][i]/=a[l][e];
	}a[l][e]=1/a[l][e];
	for(int i=0;i<=n+f;i++){
		if(i==l)continue;
		for(int j=0;j<=m+f;j++){
			if(j==e)continue;
			a[i][j]-=a[i][e]*a[l][j];
		}a[i][e]*=-a[l][e];
	}
}
bool init(){
	int pos=-1;
	double minn=1e300;
	for(int i=1;i<=n;i++)
	if(dcmp(minn-a[i][0])==1)minn=a[i][0],pos=i;
	if(dcmp(minn)>=0)return 1;
	for(int i=0;i<=m;i++)swap(a[0][i],a[n+1][i]);
	for(int i=0;i<=n;i++)a[i][m+1]=-1;
	pivot(pos,m+1,1);
	if(!dcmp(simplex(1))){
		for(int i=1;i<=m+1;i++)if(!dcmp(a[0][i]+1)){pos=i;break;}
		for(int i=0;i<=m+1;i++)swap(a[0][i],a[n+1][i]);
		for(int i=0;i<=n+1;i++)swap(a[i][pos],a[i][m+1]);
	}else return 0;
	return 1;
}
double simplex(bool f){
	for(;;){
		int pos=-1,l,e;
		double minn=0;
		for(int i=1;i<=m+f;i++)
		if(dcmp(a[0][i]-minn)==1)minn=a[0][i],pos=i;
		if(!~pos)return -a[0][0];
		e=pos;pos=-1;minn=1e300;
		for(int i=1;i<=n;i++)
		if(dcmp(a[i][e])==1&&dcmp(a[i][0]/a[i][e]-minn)==-1)
		minn=a[i][0]/a[i][e],pos=i;
		if(!~pos){
			printf("INF!!\n");
			return 1e300;
		}l=pos;
		pivot(l,e,f);
	}
}
template<typename T>
T getint(){
	T rs=0,f=1;char c=getchar();
	while(!isdigit(c))f=f==-1||c=='-'?-1:1,c=getchar();
	while(isdigit(c))rs=(rs<<3)+(rs<<1)+c-'0',c=getchar();
	return rs*f;
}
int T;
int main(){
//	freopen("123.txt","w",stdout);
	scanf("%d",&T);
	while(T--){
		m=getint<int>();
		n=getint<int>();
		int now=0;
		int l,r,v;
		memset(a,0,sizeof(a));
		for(int j=1;j<=n;j++){
			l=getint<int>();
			r=getint<int>();
			v=getint<int>();
			a[now+1][r]=1;
			a[now+1][l-1]=-1;
			
			a[now+2][r]=-1;
			a[now+2][l-1]=1;
			
			a[now+1][0]=v+(r-l+1)*5e2;
			a[now+2][0]=-v-(r-l+1)*5e2;
			now+=2;
		}
		n+=n;
		if(init())puts("true");
		else puts("false");
	}	
	return 0;
}

AC 差分约束:

#include<bits/stdc++.h>
using namespace std;
const int maxn=110;
vector<pair<int,int> >G[maxn];
void add(int u,int v,int w){
	G[u].push_back(pair<int,int>(v,w));
	G[v].push_back(pair<int,int>(u,-w));
}
int n,m,T;
int d[maxn],vis[maxn],in[maxn];
bool spfa(){
	memset(d,0x7f,sizeof(d));
	memset(vis,0,sizeof(vis));
	memset(in,0,sizeof(in));
	d[0]=0;
	queue<int>q;
	q.push(0);vis[0]=1;
	while(!q.empty()){
		int u=q.front();q.pop();vis[u]=0;
		for(int i=0;i<G[u].size();i++){
			int v=G[u][i].first,w=G[u][i].second;
			if(d[v]>d[u]+w){
				d[v]=d[u]+w;
				if(!vis[v]){
					vis[v]=1;
					q.push(v);
					if(++in[v]>n)return 0;
				}
			}		
		}
	}return 1;
}

int main(){
	scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n,&m);
		for(int i=0;i<=n;i++)G[i].clear();
		for(int j=1;j<=m;j++){
			int l,r,v;
			scanf("%d%d%d",&l,&r,&v);
			add(l-1,r,v);
		}
		if(spfa())puts("true");
		else puts("false");
	}
	return 0;
}



你可能感兴趣的:(bzoj)