17 条题解
-
2Goodhao LV 10 @ 2018-08-05 14:03:15
感动啊终于学会差分约束了
之前理解的不到位。
本题的具体做法已经有很好的题解了,我讲一下对差分约束的理解。(如果你是像我一样拿这题入门差分约束的话可能会踩到很多坑)简单的说给定一些xi,和一些形如xi-xj<=某个常数的不等式组
差分约束就是通过bellmanford求出其中一组可行解。
这很重要,是其中一组可行解,也就是说还可以有别的解,而且你的解不一定是满足题目要求的最优性的,并且你把当前的解全部加上一个偏移量d也不一定能完全覆盖所有可行解(虽然可以得到无数组可行解)。
不过在本题中我们直接枚举答案,因此只需要存在一组可行解。差分约束建立了很多边,但是起点在哪里?怎么初始化dis呢?
做法是设立一个源点从它出发向其他所有点连权值为0的边,然后把它的dis设为0,把它当作起点。
这个做法很寻常,但是这样做的问题是,比如说你输出一下dis数组会发现为什么一些dis都是负数,但是我们的答案显然是正的,这里的dis到底是什么意思。
刚才说过我们可以通过偏移来得到无数组可行解,因为任意两个x之间的差永远不变,有点像物理里的势能一样,我们不在乎哪里是零势能,我们自行规定即可。于是我们规定一个点是零势能,点0,那么即使从我们选定的源点出发到点0的dis为负也不代表什么,这是“势能差”,要得到真正的势能,要把最终求好的所有dis加上dis[0],也就是dis[x]-dis[0]才是我们真正想要的值这个理解以后,当你想对一个x进行约束比如让它=1的时候就不会直接在dis里设置dis[x]=1
而是dis[x]-dis[0]=1,变成两个不等式:
dis[x]-dis[0]<=1
dis[0]-dis[x]<=-1 (即dis[x]-dis[0]>=1)#include <bits/stdc++.h> using namespace std; #define FOR(i,n) for (int i=1;i<=n;i++) #define REP(i,a,b) for (int i=a;i<=b;i++) #define pb push_back #define mp make_pair #define ll long long const int N=100000+10; const int inf=0x3f3f3f3f; const ll mod=7654321; const double PI=3.1415926; const double eps=1e-8; int T; int n; int need[30]; int have[30]; int d[30]; struct edge { int to,w; }; vector<edge> g[30]; void insert(int x,int y,int w) { g[x].pb(edge{y,w}); } bool bellmanford() { memset(d,0x3f,sizeof d); d[25]=0; FOR(i,26) { REP(j,0,25) { for (int k=0;k<g[j].size();k++) { int to=g[j][k].to,w=g[j][k].w; if (d[to]>d[j]+w) { if (i==26) return 1; d[to]=d[j]+w; } } } } return 0; } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); cin>>T; while (T--) { FOR(i,24) cin>>need[i]; cin>>n; memset(have,0,sizeof have); FOR(i,n) { int t;cin>>t; ++have[t+1]; } bool ok=0; REP(sum,0,n) { REP(i,0,25) g[i].clear(); REP(i,0,24) insert(25,i,0); FOR(i,24) insert(i,i-1,0); FOR(i,24) insert(i-1,i,have[i]); // s[0]=0 REP(i,8,24) insert(i,i-8,-need[i]); FOR(i,7) insert(i,i+16,sum-need[i]); insert(24,0,-sum); insert(0,24,sum); if (bellmanford()==0) { ok=1; cout<<sum<<endl; break; } } if (!ok) cout<<"No Solution"<<endl; } return 0; }
-
02017-05-08 07:58:13@
/* 差分约束 http://www.cnblogs.com/fraud/p/4304350.html 和区间一起的在论文中有 http://wenku.baidu.com/view/685fbe1e650e52ea5518981a.html?from=related */ #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <queue> using namespace std; const int MAXN=1005; const int INF=(1<<30)-1; struct Edge { int to,nxt,w; Edge() { to=nxt=w=-1; } }e[MAXN]; int first[MAXN]; int t,n; int tot; int d[MAXN]; int in[MAXN]; int cnt[MAXN]; int R[MAXN]; int num[MAXN]; int inihead[MAXN]; queue<int> q; void inline Add_Edge(int x,int y,int w) { tot++; e[tot].to=y; e[tot].w=w; e[tot].nxt=first[x]; first[x]=tot; } void init() { int a; for(int i=1;i<=24;i++) cin>>R[i]; cin>>n; memset(num,0,sizeof(num)); for(int i=1;i<=n;i++) { cin>>a; num[a+1]++; } tot=0; memset(first,-1,sizeof(first)); memset(e,-1,sizeof(-1)); for(int i=1;i<=24;i++) { if(i>7) Add_Edge(i-8,i,R[i]); Add_Edge(i,i-1,-num[i]); Add_Edge(i-1,i,0); } for(int i=0;i<25;i++) inihead[i]=first[i]; } bool SPFA(int mid) { for(int i=0;i<=24;i++) d[i]=-INF,in[i]=0,cnt[i]=0; q.push(0); in[0]=1; cnt[0]++; d[0]=0; while(!q.empty()) { int x=q.front(); q.pop(); in[x]=0; for(int i=first[x];i!=-1;i=e[i].nxt) { int y=e[i].to; int w=e[i].w; if(d[y]<d[x]+w) { d[y]=d[x]+w; if(!in[y]) { q.push(y); in[y]=1; if(++cnt[y]>25) return false; } } } } return true; } int main() { cin>>t; while(t--) { init(); int l=0,r=n; int ans=INF; while(l<r) { int mid=(l+r)/2; for(int i=0;i<25;i++) first[i]=inihead[i]; for(int i=1;i<8;i++) Add_Edge(i+16,i,R[i]-mid); Add_Edge(0,24,mid); if(SPFA(mid)) { r=mid; ans=min(ans,mid); } else l=mid+1; } if(ans>n) cout<<"No Solution"<<endl; else cout<<ans<<endl; } return 0; }
-
02009-11-06 09:02:00@
不知交了多少次.......
还是不等式写错 -
02009-11-03 20:29:11@
POJ AC的程序到这里WA了。。囧。。
-
02009-11-01 22:14:11@
为什么求最短路就是WA,求最长路就能AC?
有人求最短路能AC的么?
-
02009-10-09 11:53:49@
编译通过...
├ 测试数据 01:答案正确... 0ms
---|---|---|---|---|---|---|---|-
Accepted 有效得分:100 有效耗时:0ms差分 约束
为什么不放在图结构里? -
02009-10-06 20:43:38@
编译通过...
├ 测试数据 01:答案正确... 0ms
---|---|---|---|---|---|---|---|-
Accepted 有效得分:100 有效耗时:0ms不错的差分约束题
一点点错 我调了N久 -
02009-09-06 23:30:48@
差分约束! 非常好!
Bellmen-Ford 关键是把不等式写出来构图,楼下的同志们已经说了。
-
02009-08-02 19:40:47@
这道题难度居然只有2………………
-
02009-04-23 15:45:10@
楼上引用别人的话,至少要说明出处啊!
原文出自"2006年全国信息学冬令营讲座",
" 华中师大一附中 冯威" 大牛的论文
-- " 数与图的完美结合---|---|-浅析差分约束系统 "题解:
“这题很容易想到如下的不等式模型:设num[ i ]为i时刻能够开始工作的人数,x[ i ]为实际雇佣的人数,那么x[ I ]=r[ I ]
设s[ I ]=x[ 1 ]+x[ 2 ]…+x[ I ],得到
0 -
02009-04-23 10:13:34@
深藏不露的差分约束系统
其实很简单的……
设r[i]表示第 i 时刻需要的人数
s[i]表示从0时刻到 i 时刻一共雇佣了几人
can[i]表示第 i 时刻最多有多少人能工作
则有不等式组:
s[i]-s>=0
s-s[i]>=-can[i]
s[i]-s>=r[i]
s[i]-s>=r[i]-s[23];
因为s[23]可以表示一共雇佣了多少人,所以枚举它就行了
剩下的就是Bellman——Ford -
02009-03-23 22:24:02@
交标程是不对的...
参见06年集训队冯威大牛的论文
不过我怎么总觉得程序虽然能AC还是有问题... -
02008-12-28 16:22:39@
我是第20个AC的.
-
02008-08-12 16:25:55@
咋这么少人里
-
02007-10-10 20:27:07@
看着黑书上过的。。。
不过还是用了好多次 -
02007-09-18 18:58:49@
'No Solution'打成'No solution',WA了6次!!
输出居然看不出来!!郁闷。。。
差分约束系统,很巧妙啊。 -
-32007-09-20 22:06:54@
begin
write('NO Solution');
end.
- 1