标签:mining station on th hdu 2448 spfa km
3 5 5 6 1 2 4 1 3 3 1 4 4 1 5 5 2 5 3 2 4 3 1 1 5 1 5 3 2 5 3 2 4 6 3 1 4 3 2 2
13
题意:有m个海上基站,n个港湾,现在有n只船在n个基站里,基站与基站之间有通讯的船才可以走这条路,告诉基站之间的距离,基站与港湾的距离,现在船要回到港湾,一个港湾只能停靠一只船,而且一旦进去就不能出来了,求所有船都回到港湾要走的最短距离之和。
思路:先用最短路求出每个船的起始点到每个港湾的最短距离,并且连边,然后求二分图的最小权匹配,用KM算法。费用流也可以做,但我姿势不够优美超时了。。。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <string> #include <map> #include <stack> #include <vector> #include <set> #include <queue> #pragma comment (linker,"/STACK:102400000,102400000") #define mod 1000000009 #define INF 0x3f3f3f3f #define pi acos(-1.0) #define eps 1e-6 #define lson rt<<1,l,mid #define rson rt<<1|1,mid+1,r #define FRE(i,a,b) for(i = a; i <= b; i++) #define FREE(i,a,b) for(i = a; i >= b; i--) #define FRL(i,a,b) for(i = a; i < b; i++) #define FRLL(i,a,b) for(i = a; i > b; i--) #define mem(t, v) memset ((t) , v, sizeof(t)) #define sf(n) scanf("%d", &n) #define sff(a,b) scanf("%d %d", &a, &b) #define sfff(a,b,c) scanf("%d %d %d", &a, &b, &c) #define pf printf #define DBG pf("Hi\n") typedef long long ll; using namespace std; const int N=350; const int MAXM = 1000000; struct Edge{ int u,v,len,next; }edge[MAXM]; int n,m,k,p,num; int dis[N],head[N]; bool inq[N]; int nx,ny; //两边的点数 int g[N][N]; //二分图描述,g赋初值为-INF int linker[N],lx[N],ly[N]; //y 中各点匹配状态,x,y中的点的标号 int slack[N]; bool visx[N],visy[N]; bool flag; void init() { num=0; memset(head,-1,sizeof(head)); } void addedge(int u,int v,int len) { edge[num]={u,v,len,head[u]}; head[u]=num++; } void SPFA(int s) { int i,j; queue<int>Q; memset(inq,false,sizeof(inq)); memset(dis,INF,sizeof(dis)); Q.push(s); dis[s]=0; inq[s]=true; while (!Q.empty()) { int u=Q.front();Q.pop(); inq[u]=false; for (int i=head[u];i+1;i=edge[i].next) { int v=edge[i].v; if (dis[v]>dis[u]+edge[i].len) { dis[v]=dis[u]+edge[i].len; if (!inq[v]) { Q.push(v); inq[v]=true; } } } } } bool DFS(int x) { visx[x]=true; for (int y=0;y<ny;y++) { if (visy[y]) continue; int tmp=lx[x]+ly[y]-g[x][y]; if (tmp==0) { visy[y]=true; if (linker[y]==-1||DFS(linker[y])) { linker[y]=x; return true; } } else if (slack[y]>tmp) slack[y]=tmp; } return false; } int KM() { flag=true; memset(linker,-1,sizeof(linker)); memset(ly,0,sizeof(ly)); for (int i=0;i<nx;i++) //赋初值,lx置为最大值 { lx[i]=-INF; for (int j=0;j<ny;j++) { if (g[i][j]>lx[i]) lx[i]=g[i][j]; } } for (int x=0;x<nx;x++) { for (int i=0;i<ny;i++) slack[i]=INF; while (true) { memset(visx,false,sizeof(visx)); memset(visy,false,sizeof(visy)); if (DFS(x)) break; int d=INF; for (int i=0;i<ny;i++) if (!visy[i]&&d>slack[i]) d=slack[i]; for (int i=0;i<nx;i++) if (visx[i]) lx[i]-=d; for (int i=0;i<ny;i++) { if (visy[i]) ly[i]+=d; else slack[i]-=d; } } } int res=0; for (int i=0;i<ny;i++) { if (linker[i]==-1||g[linker[i]][i]<=-INF) //有的点不能匹配的话return-1 { flag=false; continue; } res+=g[linker[i]][i]; } return res; } //记得nx和ny初始化!!!!!!!! int start[N]; int main() { #ifndef ONLINE_JUDGE freopen("C:/Users/asus1/Desktop/IN.txt","r",stdin); #endif int i,j,u,v,cost; while (~scanf("%d%d%d%d",&n,&m,&k,&p)) { init(); nx=n; ny=n; for (i=0;i<n+m+10;i++) for (j=0;j<n+m+10;j++) g[i][j]=-INF; for (i=1;i<=n;i++) sf(start[i]); for (i=0;i<k;i++) { sfff(u,v,cost); addedge(u,v,cost); //站点之间的便可以走多次 addedge(v,u,cost); } for (i=0;i<p;i++) { sfff(u,v,cost); addedge(v,u+m,cost); //注意这里是单向边,因为港口只进不出 } for (i=1;i<=n;i++) { SPFA(start[i]); //SPFA求出每个船起始位置到港湾的最短距离 for (j=1;j<=n;j++) { if (dis[j+m]!=INF) g[i-1][j-1]=-dis[j+m]; // else // g[i-1][j-1]=0; } } int ans=KM(); printf("%d\n",-ans); } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
Mining Station on the Sea (hdu 2448 SPFA+KM)
标签:mining station on th hdu 2448 spfa km
原文地址:http://blog.csdn.net/u014422052/article/details/46832801