终于会dij了原来我以前写的也是堆优化spfa-_-!
poj3662DP 通过spfa来放缩(可怜我去年NOIP的day1t3啊)
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; struct node { int x,y,d,next; }a[21000];int len,last[1100]; void ins(int x,int y,int d) { len++; a[len].x=x;a[len].y=y;a[len].d=d; a[len].next=last[x];last[x]=len; } int list[1100]; int f[1100][1100];bool v[1100]; int main() { int n,m,K,x,y,d; scanf("%d%d%d",&n,&m,&K); len=0;memset(last,0,sizeof(last)); for(int i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&d); ins(x,y,d);ins(y,x,d); } int head=1,tail=2;list[1]=1; memset(f,63,sizeof(f));f[1][0]=0; memset(v,false,sizeof(v));v[1]=true; while(head!=tail) { int x=list[head]; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; for(int p=0;p<=K;p++) { int tt=f[y][p]; if(p!=0)f[y][p]=min(f[y][p],f[x][p-1]); f[y][p]=min(f[y][p],max(f[x][p],a[k].d)); if(tt!=f[y][p]&&v[y]==false) { v[y]=true; list[tail]=y; tail++;if(tail==1050)tail=1; } } } v[x]=false; head++;if(head==1050)head=1; } if(f[n][K]==f[0][0])printf("-1 "); else printf("%d ",f[n][K]); return 0; }
最优贸易 正反dij分别求最小和最大,然后mx[x]-mn[x]就好(怎么这个专题净勾起我的伤心事啊,初一的某模拟赛就是没还原v数组100变没分啊啊啊)
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> #include<queue> using namespace std; struct node{int x,y,next;}a[1100000],e[1100000]; int alen,elen,alast[110000],elast[110000]; void ains(int x,int y) { alen++; a[alen].x=x;a[alen].y=y; a[alen].next=alast[x];alast[x]=alen; } void eins(int x,int y) { elen++; e[elen].x=x;e[elen].y=y; e[elen].next=elast[x];elast[x]=elen; } struct dij { int k,id; dij(){} dij(int K,int ID){k=K;id=ID;} friend bool operator>(dij d1,dij d2){return d1.k>d2.k;} friend bool operator<(dij d1,dij d2){return d1.k<d2.k;} }; priority_queue<dij,vector<dij>,greater<dij> >aq; priority_queue<dij>eq; int mn[110000],mx[110000];bool v[110000],inq[110000]; int w[110000]; int main() { int n,m,x,y,op; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)scanf("%d",&w[i]); alen=0;memset(alast,0,sizeof(alast)); elen=0;memset(elast,0,sizeof(elast)); for(int i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&op); if(op==1) ains(x,y), eins(y,x); else ains(x,y),ains(y,x), eins(x,y),eins(y,x); } memset(v,false,sizeof(v)); memset(inq,false,sizeof(inq));inq[1]=true; mn[1]=w[1]; aq.push(dij(w[1],1)); while(!aq.empty()) { dij tno=aq.top();aq.pop(); if(v[tno.id]==true)continue; v[tno.id]=true; int x=tno.id; for(int k=alast[x];k;k=a[k].next) { int y=a[k].y; if(inq[y]==false) inq[y]=true, mn[y]=w[y], aq.push(dij(mn[y],y)); if(mn[y]>tno.k) { mn[y]=tno.k; aq.push(dij(mn[y],y)); } } } memset(v,false,sizeof(v)); memset(inq,false,sizeof(inq));inq[1]=true; mx[n]=w[n], eq.push(dij(w[n],n)); while(!eq.empty()) { dij tno=eq.top();eq.pop(); if(v[tno.id]==true)continue; v[tno.id]=true; int x=tno.id; for(int k=elast[x];k;k=e[k].next) { int y=e[k].y; if(inq[y]==false) inq[y]=true, mx[y]=w[y], eq.push(dij(mx[y],y)); if(mx[y]<tno.k) { mx[y]=tno.k; eq.push(dij(mx[y],y)); } } } int ans=0; for(int i=1;i<=n;i++) ans=max(ans,mx[i]-mn[i]); printf("%d ",ans); /* for(int i=1;i<=n;i++)printf("%d ",mx[i]); printf(" "); for(int i=1;i<=n;i++)printf("%d ",mn[i]); printf(" ");*/ return 0; }
bzoj2200 这题卡spfa(然而用酸辣粉和啦(fan)啦(you)啦(hua)这两个玄学优化可以过)
正解呢是topsort+dij,因为把正边看成联通块,负边其实构成的是一个DAG图,所以拓扑排序时顺便把环dij一次
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> #include<queue> using namespace std; struct node { int x,y,d,next; }a[110000];int len,last[31000]; void ins(int x,int y,int d) { len++; a[len].x=x;a[len].y=y;a[len].d=d; a[len].next=last[x];last[x]=len; } int fa[31000]; int findfa(int x) { if(fa[x]==x)return x; fa[x]=findfa(fa[x]);return fa[x]; } int d[31000]; struct dij { int k,id; dij(){} dij(int K,int ID){k=K;id=ID;} friend bool operator>(dij d1,dij d2){return d1.k>d2.k;} friend bool operator<(dij d1,dij d2){return d1.k<d2.k;} }; bool v[31000]; priority_queue<dij,vector<dij>,greater<dij> >q; void dijkstra(int st,int k) { if(d[st]<=k)return ; d[st]=k;q.push(dij(d[st],st)); memset(v,false,sizeof(v)); while(!q.empty()) { dij tno=q.top();q.pop(); if(v[tno.id]==true)continue; v[tno.id]=true; int x=tno.id; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(d[y]>d[x]+a[k].d) { d[y]=d[x]+a[k].d; q.push(dij(d[y],y)); } } } } //----------------合并成联通块+dijkstra处理正环--------------------- struct enode { int fx,fy,x,y,d,next; }e[110000];int elen,elast[31000]; void eins(int fx,int fy,int x,int y,int d) { elen++; e[elen].fx=fx;e[elen].fy=fy; e[elen].x=x;e[elen].y=y;e[elen].d=d; e[elen].next=elast[fx];elast[fx]=elen; } int du[31000],n,S; int top,sta[31000]; void topsort() { top=0;sta[++top]=0; eins(0,findfa(S),0,S,0),du[findfa(S)]++; for(int i=1;i<=n;i++) if(findfa(i)==i&&du[i]==0&&i!=findfa(S)) sta[++top]=i; while(top!=1) { int fx=sta[top];top--; for(int k=elast[fx];k;k=e[k].next) { du[e[k].fy]--; if(du[e[k].fy]==0)sta[++top]=e[k].fy; } } while(top!=0) { int fx=sta[top];top--; for(int k=elast[fx];k;k=e[k].next) { dijkstra(e[k].y,d[e[k].x]+e[k].d); du[e[k].fy]--; if(du[e[k].fy]==0)sta[++top]=e[k].fy; } } } //--------------topsort-------------------- int main() { int R,P,x,y,dd; scanf("%d%d%d%d",&n,&R,&P,&S); len=0;memset(last,0,sizeof(last)); for(int i=1;i<=n;i++)fa[i]=i; for(int i=1;i<=R;i++) { scanf("%d%d%d",&x,&y,&dd); ins(x,y,dd);ins(y,x,dd); int fx=findfa(x),fy=findfa(y); fa[fx]=fy; } memset(du,0,sizeof(du)); for(int i=1;i<=P;i++) { scanf("%d%d%d",&x,&y,&dd); int fx=findfa(x),fy=findfa(y); eins(fx,fy,x,y,dd); du[fy]++; } memset(d,63,sizeof(d));d[0]=0; topsort(); for(int i=1;i<=n;i++) if(d[i]==d[n+1])printf("NO PATH "); else printf("%d ",d[i]); return 0; }
poj1734 floyd求最小环,考虑对于一个环,把它拆分成前k-1个点和第k个点,当floyd完k-1次,得到的就是利用前k-1个点相互到达的最短路,此时再加上第k个点构成环,保证不重复,同时,取最大的点和取其他点,效果是一样的。
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; int a[110][110],mp[110][110]; int len,as[110],pos[110][110]; void getpath(int i,int j) { if(pos[i][j]==0)return ; getpath(i,pos[i][j]); as[++len]=pos[i][j]; getpath(pos[i][j],j); } int main() { freopen("TRIP.in","r",stdin); freopen("TRIP.out","w",stdout); int n,m,x,y,d; scanf("%d%d",&n,&m); memset(mp,63,sizeof(mp)); for(int i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&d); mp[x][y]=min(mp[x][y],d); mp[y][x]=min(mp[y][x],d); } memcpy(a,mp,sizeof(mp)); int ans=mp[0][0]; memset(pos,0,sizeof(pos)); for(int k=1;k<=n;k++) { for(int i=1;i<k;i++) for(int j=i+1;j<k;j++) { if((long long)mp[i][j]+a[i][k]+a[k][j]<ans) { ans=mp[i][j]+a[i][k]+a[k][j]; len=0; as[++len]=i; getpath(i,j); as[++len]=j; as[++len]=k; } } for(int i=1;i<=n;i++) if(i!=k) for(int j=1;j<=n;j++) if(j!=k&&j!=i) if(mp[i][j]>mp[i][k]+mp[k][j]) { mp[i][j]=mp[i][k]+mp[k][j]; pos[i][j]=k; } } if(ans==mp[0][0])printf("No solution. "); else { for(int i=1;i<len;i++)printf("%d ",as[i]); printf("%d ",as[len]); } return 0; }
poj3613 神仙题
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; struct line{int d,x,y;}li[110]; int n,ls[210]; struct Matrix{int mp[110][110];}A,ans; Matrix calc(Matrix a,Matrix b) { Matrix c; memset(c.mp,63,sizeof(c.mp)); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) for(int k=1;k<=n;k++) c.mp[i][j]=min(c.mp[i][j],a.mp[i][k]+b.mp[k][j]); return c; } int main() { int m,P,S,E; scanf("%d%d%d%d",&P,&m,&S,&E); n=0; for(int i=1;i<=m;i++) { scanf("%d%d%d",&li[i].d,&li[i].x,&li[i].y); ls[++n]=li[i].x; ls[++n]=li[i].y; } sort(ls+1,ls+n+1); n=unique(ls+1,ls+n+1)-ls-1; for(int i=1;i<=m;i++) { li[i].x=lower_bound(ls+1,ls+n+1,li[i].x)-ls; li[i].y=lower_bound(ls+1,ls+n+1,li[i].y)-ls; } S=lower_bound(ls+1,ls+n+1,S)-ls; E=lower_bound(ls+1,ls+n+1,E)-ls; //LSH memset(A.mp,63,sizeof(A.mp)); for(int i=1;i<=m;i++) { int x=li[i].x,y=li[i].y; A.mp[x][y]=min(A.mp[x][y],li[i].d); A.mp[y][x]=min(A.mp[y][x],li[i].d); } memcpy(ans.mp,A.mp,sizeof(A.mp)); P--; while(P!=0) { if(P%2==1)ans=calc(ans,A); A=calc(A,A);P/=2; } printf("%d ",ans.mp[S][E]); return 0; }