總體感覺,痛點是建圖,因為建圖的時候需要考慮一些題目上沒有明確給出的隱含條件,只有把所有約束關係找全之後,然後再正確運用最短路(或者最長路)的性質求解,才能得到正確答案。
說說我的收穫:
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:busing 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;}
POJ3169 Layout
這個題目,對於點上的元素個數,特意給出了說明,可以有任意多個元素在同一個點上,所以不用加邊,直接建圖求最短路即可。
代碼:
#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;}
POJ1275/ZOJ1420/HDU1529 Cashier Employment
黑書上的例題,老經典了,也老難了,我糾結了好久才出來……
這題建圖有難度,一般不容易想到所有的約束條件,看了黑書講解,然後又搜了報告,才做出來的,所以不貼我醜陋的代碼了,給個解題報告看看吧,挺不錯的。
感謝:
http://hi.baidu.com/accplaystation/blog/item/7c6d10136ef28b856438db6b.html
http://happylch21.blog.163.com/blog/static/165639759201163084924988/