差分约束合集

hdu 4598 Difference

一开始没看题目中的<=> 符号,各种错误。实际上可化简为典型的判断差分约束有无解的问题,需要用到SPFA。
#include<cstdio>
#include<algorithm>
#include<vector>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int MAXN = 305;
int n, res, TT = 1000;
int mmp[MAXN];
char str[MAXN][MAXN];
struct node{int v; int w;};
vector<node> head[MAXN];
void dfs(int u, int c)
{
	if (!res) return;
	mmp[u] = c;
	for (int i = 0, len = head[u].size(); i< len; ++i)
	{
		int v = head[u][i].v;
		if (mmp[v] != 0)
		{
			if (mmp[v] + c != 0)
			{
				res = 0;
				return;
			}
		}
		else
		{
			dfs(v, 0-c);
		}
	}
}
int qq[MAXN*MAXN], bg, ed, vis[MAXN], dis[MAXN], cnt[MAXN];
int spfa()
{
	int st = n;
	bg = ed = 0;
	for (int i = 0; i< n; ++i) vis[i]=0, dis[i]=TT*TT, cnt[i]=0;
	vis[st] = 1; dis[st] = 0; qq[ed++] = st; cnt[st]++;
	while (bg < ed)
	{
		int u = qq[bg++];
		vis[u] = 0;		
		for (int i = 0, len = head[u].size(), v; i< len; ++i)
		{
			v=head[u][i].v;
			if (dis[u]+head[u][i].w < dis[v])
			{
				dis[v] = dis[u]+head[u][i].w;
				if (!vis[v])
				{
					vis[v] = 1; qq[ed++] = v; cnt[v]++;
					if (cnt[v] > n) return 0;
				}
			}			
		}
	}
	return 1;
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("in.txt", "r", stdin);
#endif
	int t;
	scanf("%d", &t);
	while (t--)
	{
		scanf("%d", &n);
		for (int i = 0; i< n; ++i)
		{
			scanf("%s", str[i]);
			head[i].clear();
			node tp;
			for (int j = 0; j< n; ++j)
			{
				if (str[i][j] == '1') tp.v = j, head[i].push_back(tp);
			}
		}
		memset(mmp, 0, sizeof mmp);
		res = 1;
		for (int i = 0; i< n; ++i)
		{
			if (!mmp[i]) dfs(i, 1);
		}
		if(res == 1)
		{
			node tp;
			for (int i = 0; i<= n; ++i) head[i].clear();
			for (int i = 0; i< n; ++i)
			{
				for (int j = 1+i; j< n; ++j)
				{					
					if (str[i][j] == '0')
					{
						if (mmp[i] == 1)
						{
							tp.v = i; tp.w = TT-1;
							head[j].push_back(tp); 
							//printf("%d %d %d\n", j, tp.v, tp.w);
						}
						else
						{
							tp.v = j; tp.w = TT-1;
							head[i].push_back(tp);
							//printf("%d %d %d\n", i, tp.v, tp.w);
						}
					}
					else
					{
						if (mmp[i] == 1) // positive
						{
							tp.v = j; tp.w = -TT;
							head[i].push_back(tp);
							//printf("%d %d %d\n", i, tp.v, tp.w);
						}
						else
						{
							tp.v = i; tp.w = -TT;
							head[j].push_back(tp);
							//printf("%d %d %d\n", j, tp.v, tp.w);
						}
					}
				}
			}
			for (int i = 0; i< n; ++i)
			{
				tp.v = i; tp.w = 0;
				head[n].push_back(tp);
			}
			if (spfa()) puts("Yes");
			else puts("No");
		}
		else puts("No");
	}
	return 0;
}


hdu 3592 World Exhibition

典型的差分约束,需要注意的是因为涉及到求点之间距离,所以无需添加一个源点使其与所有定点相连且边权均为0。
#include<cstdio>
#include<algorithm>
#include<vector>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int MAXN = 1005;
const int INF = 1<<30;
struct eg{int v, w;};
vector<eg> e[MAXN];
int n, vis[MAXN], dis[MAXN], cnt[MAXN];
int q[MAXN*MAXN], bg, ed;
int spfa()
{
	bg = ed = 0;
	int st = 1;
	for (int i = 0; i<= n; ++i) vis[i]=0, dis[i]=INF, cnt[i]=0;
	vis[st] = 1, dis[st] = 0, cnt[st]++, q[ed++]=st;
	while (bg < ed)
	{
		int u = q[bg++];
		vis[u] = 0;
		for (int i = 0, len = e[u].size(), v; i< len; ++i)
		{
			v = e[u][i].v;
			if (dis[v] > dis[u] + e[u][i].w)
			{
				dis[v] = dis[u] + e[u][i].w;
				if (!vis[v])
				{
					vis[v] = 1;
					q[ed++] = v;
					cnt[v]++;
					if (cnt[v] > n) return -1;
				}
			}
		}
	}
	if(dis[n] == INF) return -2;
	return dis[n];
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("in.txt", "r", stdin);
#endif
	int t;
	scanf("%d", &t);
	while (t--)
	{
		int x, y;
		eg tp;
		scanf("%d%d%d", &n, &x, &y);
		for (int i = 1; i<= n; ++i)
		{
			e[i].clear();
			if ( i > 1) tp.v = i-1, tp.w = 0, e[i].push_back(tp);
		}
		for (int i= 0; i< x; ++i)
		{
			int a, b, c;
			scanf("%d%d%d", &a, &b, &c);
			tp.v = b; tp.w = c;
			e[a].push_back(tp);
		}
		for (int i = 0; i< y; ++i)
		{
			int a, b, c;
			scanf("%d%d%d", &a, &b, &c);
			tp.v = a; tp.w = -c;
			e[b].push_back(tp);
		}
		printf("%d\n", spfa());
	}
	return 0;
}


hdu 1534 Schedule Problem

没什么好说的,需要加个源点
#include<cstdio>
#include<algorithm>
#include<vector>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int MAXN = 100005;
const int INF = 1<<30;
struct eg{int v, w;};
vector<eg> e[MAXN];
int n, vis[MAXN], dis[MAXN], cnt[MAXN], last[MAXN];
int q[MAXN*10], bg, ed;
int spfa()
{
	bg = ed = 0;
	int st = 0;
	for (int i = 0; i<= 2*n; ++i) vis[i]=0, dis[i]=INF, cnt[i]=0;
	vis[st] = 1, dis[st] = 0, cnt[st]++, q[ed++]=st;
	while (bg < ed)
	{
		int u = q[bg++];
		vis[u] = 0;
		for (int i = 0, len = e[u].size(), v; i< len; ++i)
		{
			v = e[u][i].v;
			if (dis[v] > dis[u] + e[u][i].w)
			{
				dis[v] = dis[u] + e[u][i].w;
				if (!vis[v])
				{
					vis[v] = 1;
					q[ed++] = v;
					cnt[v]++;
					if (cnt[v] > 2*n)
						return 0;
				}
			}
		}
	}
	return 1;
}
char ss[20];
int main()
{
#ifndef ONLINE_JUDGE
	freopen("in.txt", "r", stdin);
#endif
	int cs = 1;
	while (scanf("%d", &n) && n != 0)
	{
		eg tp;
		if (cs != 1) puts("");
		printf("Case %d:\n", cs++);
		for (int i = 0; i<= 2*n; ++i) e[i].clear();
		for (int i = 1; i<= n; ++i)
		{
			int tt;			
			scanf("%d", &tt); last[i] = tt;
			tp.v = 2*i-1; tp.w = -tt;
			e[2*i].push_back(tp);
			tp.v = 2*i; tp.w = tt;
			e[2*i-1].push_back(tp);
			tp.v = 2*i; tp.w = 0;
			e[0].push_back(tp);
			tp.v = 2*i-1;
			e[0].push_back(tp);
		}
		while(1)
		{
			scanf("%s", ss);
			if (strcmp(ss, "#") == 0) break;
			int a, b;
			scanf("%d%d", &a, &b);
			if (strcmp(ss, "FAS") == 0)
			{
				tp.v = 2*b-1; tp.w = 0;
				e[2*a].push_back(tp);
			}
			else if ( strcmp(ss, "FAF") == 0)
			{
				tp.v = 2*b; tp.w = 0;
				e[2*a].push_back(tp);				
			}
			else if (strcmp(ss, "SAF") == 0)
			{
				tp.v = 2*b; tp.w = 0;
				e[2*a-1].push_back(tp);
			}
			else	// SAS
			{
				tp.v = 2*b-1; tp.w = 0;
				e[2*a-1].push_back(tp);
			}
		}
		if (!spfa()) puts("impossible");
		else
		{
			int k = 0, mm = INF;
			for (int i =1; i<= 2*n; ++i)
			{
				if (dis[i] == INF)
				{
					puts("impossible");
					k = 1;
					break;					
				}
				if (i & 1)
				{
					if (dis[i] < mm)
						mm = dis[i];
				}
			}
			if (!k)
			{
				for (int i = 1, j=1; i<= 2*n; i+=2,++j)
				{
					printf("%d %d\n", j, dis[i]-mm);
				}
			}
		}
	}
	return 0;
}


hdu 1529 Cashier Employment

差分约束的核心是找出所有符合条件的变量两两之间的关系。
算是好题,如何把多元关系式转化为二元不等式废了不少功夫
#include<cstdio>
#include<algorithm>
#include<vector>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int MAXN = 50;
const int INF = 1<<30;
struct eg{int v, w;};
vector<eg> e[MAXN];
int n, vis[MAXN], dis[MAXN], cnt[MAXN];
int q[10000], bg, ed;
int ready[MAXN], need[MAXN];
int spfa(int num)
{
	for (int i = 0; i<= 7; ++i)
	{
		eg tp; tp.v = i+16; tp.w = num-need[i];
		e[i].push_back(tp);
	}
	bg = ed = 0;
	int st = 24;
	for (int i = 0; i<= 30; ++i) vis[i]=0, dis[i]=INF, cnt[i]=0;
	vis[st] = 1, dis[st] = 0, cnt[st]++, q[ed++]=st;
	while (bg < ed)
	{
		int u = q[bg++];
		vis[u] = 0;
		for (int i = 0, len = e[u].size(), v; i< len; ++i)
		{
			v = e[u][i].v;
			if (dis[v] > dis[u] + e[u][i].w)
			{
				dis[v] = dis[u] + e[u][i].w;
				if (!vis[v])
				{
					vis[v] = 1;
					q[ed++] = v;
					cnt[v]++;
					if (cnt[v] > 25)
						return 0;
				}
			}
		}
	}
	return 1;
}
void build()
{
	eg tp;
	for (int i = 0; i < 30; ++i) e[i].clear();
	for (int i = 1; i < 24; ++i)
	{
		tp.v = i-1; tp.w = 0;
		e[i].push_back(tp);
	}
	for (int i= 1; i< 24; ++i)
	{
		tp.v = i; tp.w = ready[i];
		e[i-1].push_back(tp);
	}
	for (int i = 8; i< 24; ++i)
	{
		tp.v = i-8; tp.w = -need[i];
		e[i].push_back(tp);
	}
	for (int i = 0; i< 24; ++i)
	{
		tp.v = i; tp.w = 0;
		e[24].push_back(tp);
	}
}
void bnry_sch()
{
	int high, low, mid, res = -1;
	high = n; low = 0;
	while ( low < high)
	{
		mid = (low+high)/2;
		if (spfa(mid))
		{
			res = mid;
			high = mid;
		}
		else low = mid+1;
		for (int i = 0; i<= 7; ++i)
		{
			e[i].pop_back();
		}
	}
	if (res == -1) puts("No Solution");
	else printf("%d\n", res);
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("in.txt", "r", stdin);
#endif
	int t;
	scanf("%d", &t);
	while (t--)
	{
		memset(ready, 0, sizeof ready);
		for (int i = 0; i < 24; ++i)
		{
			scanf("%d", need+i);
		}
		scanf("%d", &n);
		for (int i= 0; i < n; ++i)
		{
			int tp; scanf("%d", &tp);
			++ready[tp];
		}		
		build();
		bnry_sch();
	}
	return 0;
}


hdu 3666 THE MATRIX PROBLEM

对时间卡的比较严(用到dfs的spfa),加入源点然后判断是否有解。
L <= Cij * Ai / Bj<= U
L/Cij <= Ai / Bj<= U/Cij
L' <= Ai / Bj<= U'
log(L') <= log(Ai / Bj)<= log(U')
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cmath>
#include<queue>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int MAXN = 810;
struct node 
{
    int v, next;
    double w;
}ee[MAXN*MAXN];
int head[MAXN], ne;
int n, m;
double dis[MAXN], L, U;
bool vis[MAXN], instk[MAXN];
void add(int u, int v, double w)
{
    ee[ne].v = v; ee[ne].w = w; ee[ne].next = head[u];
    head[u] = ne++;
}
bool spfa(int u)
{
    if (instk[u]) return 0;
    instk[u] = 1;
    vis[u] = 1;
    for (int i=head[u]; ~i; i=ee[i].next)
    {
        int v = ee[i].v;
        if (dis[v] > dis[u]+ee[i].w)
        {
            dis[v] = dis[u]+ee[i].w;
            if (!spfa(v)) return false;
        }
    }
    instk[u] = 0;
    return 1;
}
bool judge()
{
    memset(vis, 0, sizeof vis);
    memset(instk, 0, sizeof instk);
    for (int i = 0; i<= n+m; ++i)
    {
        dis[i] = 0;
    }
    for (int i = 1; i<= n+m; ++i)
    {
        if (!vis[i])
        {
            if (!spfa(i)) return 0;
        }
    }
    return 1;
}
/*
    L <= Cij * Ai / Bj<= U
    L/Cij <= Ai / Bj<= U/Cij
    L' <= Ai / Bj<= U'
    log(L') <= log(Ai / Bj)<= log(U')
*/
double da[405][405];
int main()
{
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
#endif    
    while (scanf("%d%d%lf%lf", &n, &m, &L, &U) != EOF)
    {
        memset(head, -1, sizeof head);
        ne = 0;
        for (int i = 1; i<= n; ++i)
        {
            for (int j = 1; j<= m; ++j)
            {
                double c, da;
                scanf("%lf", &da);
                add(j+n, i, log(U/da));
                add(i, j+n, -log(L/da));
            }
        }
        if (!judge()) puts("NO");
        else puts("YES");
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值