总体感觉,难点是建图,因为建图的时候需要考虑一些题目上没有明确给出的隐含条件,只有把所有约束关系找全之后,然后再正确运用最短路(或者最长路)的性质求解,才能得到正确答案。
说说我的收获:
node1:对于区间放置元素问题,要注意区间开闭性,也就是说要关注对点的约束。特别注意每个点上放置元素个数的限制,这里一般都是隐含关系的考察点(详见下文)。
node2:对于差分不等式,a - b <= c ,建一条 b 到 a 的权值为 c 的边,求的是最短路,得到的是最大值;对于不等式 a - b >= c ,建一条 b 到 a 的权值为 c 的边,求的是最长路,得到的是最小值。存在负环的话是无解,求不出最短路(dist[ ]没有得到更新)的话是任意解。
node3:建图中有时候会用到一个虚点,这个点到图中每个实点的距离(dist[ ])为0,当然这个点的作用是方便图中的点入队(spfa算法),然后使这些实点的dist[ ]值得到更新,其实有时候我们可以省略这个点,手动把所有实点入队,同时更新这些实点的 dist[ ] 值和 visit[ ] 值。
POJ1201/ZOJ1508/HDU1384 Intervals(解题报告)
这道题就是整数区间问题,典型的差分约束问题,题目要求了每个点要么不放元素,要么放一个元素,那么我们就可以根据这个要求加边:0 <= s[ i+1 ] - s[ i ] <= 1 。这就是上面说的隐含条件的应用。
POJ1716 Integer Intervals
这个题是上面那个的阉割版,把每个区间端点的大小关系设为了定值,其他的一样。
#include<cstdio> #include<cstring> #include<climits> #include<algorithm> #include<queue> #define min(a,b) a<b?a:b #define max(a,b) a>b?a:b using namespace std; const int N = 10010; struct Edge{ int s,e,v,next; }edge[3*N]; int m,e_num,left,right,head[N],vis[N],dist[N]; void AddEdge(int a,int b,int c){ edge[e_num].s=a; edge[e_num].e=b; edge[e_num].v=c; edge[e_num].next=head[a]; head[a]=e_num++; } queue <int> q; void getmap(){ int i,a,b; e_num=0; left=INT_MAX; right=INT_MIN; memset(head,-1,sizeof(head)); while(m--){ scanf("%d%d",&a,&b); AddEdge(a,b+1,2); left=min(left,a); right=max(right,b); } for(i=left;i<=right;i++){ AddEdge(i,i+1,0); AddEdge(i+1,i,-1); } for(i=left;i<=right;i++){ q.push(i); vis[i]=1; dist[i]=0; } } void spfa(){ int i; while(!q.empty()){ int cur=q.front(); q.pop(); vis[cur]=0; for(i=head[cur];i!=-1;i=edge[i].next){ int u=edge[i].e; if(dist[u]-dist[cur]<edge[i].v){ dist[u]=dist[cur]+edge[i].v; if(!vis[u]){ q.push(u); vis[u]=1; } } } } printf("%d\n",dist[right+1]); } int main() { while(~scanf("%d",&m)) { getmap(); spfa(); } return 0; }
POJ1364/ZOJ1260 King(解题报告)
详见结题报告
POJ3159 Candies
这个题不卡建图,所有约束关系都给你了,只要根据给的不等式建边就好,不过,用spfa的话,需要注意,队列会超时的……
貌似是出数据的故意这么玩的,改成栈吧,由于栈和队的性质差异(一个后进先出,一个先进先出),所以对于卡队列的数据用栈可以秒杀,当然反过来也一样,我这个题开始用的是队列spfa,超时了,听大神 XH 指点,把队改成栈,就A了,效率还不错。当然作为一个“正直”的ACMer而言,我们不能假设数据是仁慈的,所以用 heap 吧,旱涝保收。
代码:
#include<cstdio> #include<stack> #include<climits> #include<cstring> using namespace std; const int N = 30010; struct Edge{ int s,e,next,v; }edge[5*N]; int e_num,dist[N],vis[N],head[N]; void AddEdge(int a,int b,int c){ edge[e_num].s=a; edge[e_num].e=b; edge[e_num].v=c; edge[e_num].next=head[a]; head[a]=e_num++; } void spfa(int n){ int i; stack <int>q; memset(vis,0,sizeof(vis)); for(i=1;i<=n;dist[i++]=INT_MAX); q.push(1);vis[1]=1; dist[1]=0; while(!q.empty()){ int cur=q.top(); q.pop(); vis[cur]=0; for(i=head[cur];i!=-1;i=edge[i].next){ int u=edge[i].e; if(dist[u]-dist[cur]>edge[i].v){ dist[u]=dist[cur]+edge[i].v; if(!vis[u]){ q.push(u); vis[u]=1; } } } } printf("%d\n",dist[n]); } int main() { int n,m,a,b,c; scanf("%d%d",&n,&m); e_num=0; memset(head,-1,sizeof(head)); while(m--){ scanf("%d%d%d",&a,&b,&c); AddEdge(a,b,c); } spfa(n); return 0; }
这个题目,对于点上的元素个数,特意给出了说明,可以有任意多个元素在同一个点上,所以不用加边,直接建图求最短路即可。
代码:
#include<cstdio> #include<cstring> #include<climits> #include<algorithm> #include<queue> using namespace std; const int N = 1010; struct Edge{ int s,e,v,next; }edge[20*N]; int n,ml,md,e_num,head[N],vis[N],dist[N],countx[N]; void AddEdge(int a,int b,int c){ edge[e_num].s=a; edge[e_num].e=b; edge[e_num].v=c; edge[e_num].next=head[a]; head[a]=e_num++; } void getmap(){ int i,a,b,c; e_num=0; memset(head,-1,sizeof(head)); while(ml--){ scanf("%d%d%d",&a,&b,&c); AddEdge(a,b,c); } while(md--){ scanf("%d%d%d",&a,&b,&c); AddEdge(b,a,-c); } for(i=2;i<=n;i++) AddEdge(i,1,0); } void spfa(){ int i; queue <int> q; memset(vis,0,sizeof(vis)); memset(countx,0,sizeof(countx)); for(i=1;i<=n;dist[i++]=INT_MAX); dist[1]=0; vis[1]=1; countx[1]++; q.push(1); int tmp=0; while(!q.empty()){ int cur=q.front(); q.pop(); vis[cur]=0; if(countx[cur]>n){ tmp=-1;break; } for(i=head[cur];i!=-1;i=edge[i].next){ int u=edge[i].e; if(dist[u]-dist[cur]>edge[i].v){ dist[u]=dist[cur]+edge[i].v; if(!vis[u]){ q.push(u); vis[u]=1; countx[u]++; } } } } if(tmp==-1)printf("%d\n",tmp); else printf("%d\n",dist[n]<INT_MAX?dist[n]:-2); } int main() { scanf("%d%d%d",&n,&ml,&md); getmap(); spfa(); return 0; }
黑书上的例题,老经典了,也老难了,我纠结了好久才出来……
这题建图有难度,一般不容易想到所有的约束条件,看了黑书讲解,然后又搜了报告,才做出来的,所以不贴我丑陋的代码了,给个解题报告看看吧,挺不错的。
感谢:
http://hi.baidu.com/accplaystation/blog/item/7c6d10136ef28b856438db6b.html
http://happylch21.blog.163.com/blog/static/165639759201163084924988/