弗洛伊德Floyd求最小環
阿新 • • 發佈:2018-10-02
lse urn view ide 不存在 eps 圖片 none 枚舉
模板:
#include<bits/stdc++.h> using namespace std; const int MAXN = 110; const int INF = 0xffffff0; int temp,Map[MAXN][MAXN],Dist[MAXN][MAXN],pre[MAXN][MAXN],ans[MAXN*3]; void Solve(int i,int j,int k) { temp = 0; //回溯,存儲最小環 while(i != j) { ans[temp++] = j; jView Code= pre[i][j]; } ans[temp++] = i; ans[temp++] = k; } void Floyd(int N) { for(int i = 1; i <= N; ++i) for(int j = 1; j <= N; ++j) { Dist[i][j] = Map[i][j]; pre[i][j] = i; } int MinCircle = INF; //最小環 for(int k = 1; k <= N; ++k) { for(int i = 1; i <= N; ++i) { for(int j = 1; j <= N; ++j) { if(i != j && Dist[i][j] != INF && Map[i][k] != INF && Map[k][j] != INF && Dist[i][j] + Map[i][k] + Map[k][j] < MinCircle) { MinCircle= min(MinCircle, Dist[i][j] + Map[i][k] + Map[k][j]); Solve(i,j,k); //回溯存儲最小環 } } } for(int i = 1; i <= N; ++i) { for(int j = 1; j <= N; ++j) { if(Dist[i][k] != INF && Dist[k][j] != INF && Dist[i][k] + Dist[k][j] < Dist[i][j]) { Dist[i][j] = Dist[i][k] + Dist[k][j]; pre[i][j] = pre[k][j]; //記錄點i到點j的路徑上,j前邊的點 } } } } if(MinCircle == INF) //不存在環 { printf("No solution.\n"); return; } //如果求出最小環為負的,原圖必定存在負環 for(int i = 0;i < temp; ++i) //輸出最小環 if(i != temp-1) printf("%d ",ans[i]); else printf("%d\n",ans[i]); }
例題:
BZOJ1027: [JSOI2007]合金
思路:給定兩個點集A和B,求A中最小的一個子集S,使B中所有的點在S的凸包內部。枚舉A點集兩點i,j(i可以等於j)若B點集中的所有點都在向量i->j的左側或線段ij上,就連接一條i->j的單向邊,然後Floyd求最小環即可。
#include<bits/stdc++.h> #define eps 1e-8 using namespace std; struct node { double x,y,z; }a[510],b[510]; double multi(node p1,node p2,node p0) { double x1=p1.x-p0.x; double y1=p1.y-p0.y; double x2=p2.x-p0.x; double y2=p2.y-p0.y; return x1*y2-x2*y1; } double dis(node p1,node p2) { return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)); } int d[510][510]; int main() { int n,m; scanf("%d%d",&m,&n); for(int i=1;i<=m;i++) scanf("%lf%lf%lf",&a[i].x,&a[i].y,&a[i].z); for(int i=1;i<=n;i++) scanf("%lf%lf%lf",&b[i].x,&b[i].y,&b[i].z); int i,j,k;double t; memset(d,0x3f,sizeof(d)); for(i=1;i<=m;i++) for(j=1;j<=m;j++) { for(k=1;k<=n;k++) { t=multi(a[j],b[k],a[i]); if(t<-eps) break; if( fabs(t)<eps && dis(a[i],b[k])>dis(a[i],a[j]) )break; } if(k==n+1) d[i][j]=1; } for(k=1;k<=m;k++) for(i=1;i<=m;i++)if(i!=k) for(j=1;j<=m;j++)if(j!=k) if( d[i][j]>d[i][k]+d[k][j] )d[i][j]=d[i][k]+d[k][j]; int ans=m+1; for(i=1;i<=m;i++) if(ans>d[i][i])ans=d[i][i]; if(ans==m+1)printf("-1\n");else printf("%d\n",ans); return 0; }View Code
弗洛伊德Floyd求最小環