POJ 2516

来源:互联网 发布:淘宝0元购平台 编辑:程序博客网 时间:2024/04/30 11:54

这道题目最好的方法应该是网络流来解决。但网络流社么都不记得了,所以用二分图做的。

还是不会建模。。。每个商定所需的物品可能来自不同的仓库,细化就是每一类物品可能来自不同的仓库,再细化就是每一个物品在最后的结果中都有一个在某个仓库中的物品与其匹配。所以对于每一个物品建点,商店的为x集合,仓库的为y集合。在相同的物品见连线,最后用KM求解。其实题目已经给出了提示,k很小0~3,直接对每个物品建图即可。

把所有的点按一个整体求了一次KM,超时(虽然已经知道会超时了),然后整个图其实是有几个没有任何边相互连接的的独立的子图构成的,每一类物品构成一个独立的子图,所以可以对每个子图分别的进行最大完美匹配。

还有一个就是每一类的物品在商店中的数目如果大于在仓库中的数目的话,直接跳出终止,不成立。但认为最坏的情况下也没什么效果,所以就没加,超时。加了之后200多ms,以后能优化的地方要尽量优化。

#include <iostream>#include <cstdio>#include <cstring>#include <queue>#include <algorithm>#include <cmath>#include <stack>#include <vector>#define LL long long#define myabs(x) ((x)>0?(x):(-(x)))using namespace std;const int inf=0x3f3f3f3f;const int maxn=50*3+10;struct Edge { int v,next; };int g[maxn][maxn];const int maxm=50+10;int dis[maxm][maxm][maxm];struct node { int num,be; };node ma1[maxn],ma2[maxn];int n,m,k;int loc1[maxn][maxn],loc2[maxn][maxn];int amount1[maxn],amount2[maxn];int S[maxn],T[maxn];int lv[maxn],rv[maxn],leftp[maxn];int slack;int tot1,tot2;void update(){int i;for(i=1;i<=tot1;i++) if(S[i]) lv[i]-=slack;    for(i=1;i<=tot2;i++)  if(T[i]) rv[i]+=slack; }int match(int u){    S[u]=1;int i,j;for(i=1;i<=tot2;i++)    {if(lv[u]+rv[i]==g[u][i])        {            if(!T[i])            {                T[i]=1;                if(leftp[i]==-1||match(leftp[i]))                {                    leftp[i]=u;                    return 1;                }            }        }else slack=min(lv[u]+rv[i]-g[u][i],slack);    }    return 0;}int  solve(){    int i,j;memset(leftp,-1,sizeof(leftp));for(i=1;i<=tot1;i++) lv[i]=0;for(i=1;i<=tot2;i++) rv[i]=0;for(i=1;i<=tot1;i++)    {for(j=1;j<=tot2;j++)lv[i]=max(lv[i],g[i][j]);    }for(i=1;i<=tot1;i++)    {        for(;;)        {for(j=1;j<=tot1;j++)  S[j]=0;for(j=1;j<=tot2;j++) T[j]=0;            slack=inf;            if(match(i)) break;if(slack==inf) return -inf; update();        }    }    int sum=0;    for(i=1;i<=tot1;i++) sum+=lv[i];for(i=1;i<=tot2;i++) sum+=rv[i];    return sum;}int main(){while(~scanf("%d%d%d",&n,&m,&k)){if(!n&&!m&&!k) break;int i,j;memset(amount1,0,sizeof(amount1));memset(amount2,0,sizeof(amount2));int tem,p;for(i=1;i<=n;i++)for(j=1;j<=k;j++){scanf("%d",&tem);for(p=0;p<tem;p++)loc1[j][++amount1[j]]=i;}for(i=1;i<=m;i++){for(j=1;j<=k;j++){scanf("%d",&tem);for(p=0;p<tem;p++)loc2[j][++amount2[j]]=i;}}for(p=1;p<=k;p++)for(i=1;i<=n;i++)for(j=1;j<=m;j++)scanf("%d",&dis[i][j][p]);int sum=0;for(p=1;p<=k;p++){tot1=amount1[p]; tot2=amount2[p];if(tot1>tot2) break;for(i=1;i<=tot1;i++){for(j=1;j<=tot2;j++){g[i][j]=-dis[loc1[p][i]][loc2[p][j]][p];}}tem=-solve();if(tem==inf) break;sum+=tem;}if(p<=k) printf("-1\n");else printf("%d\n",sum);}return 0;}


原创粉丝点击