BZOJ 1070: [SCOI2007]修车
keyword:怎样建图?怎样转换网络流;
如果想到网络流的话 ,就知道是费用流。
然后怎么建图;
我们有以下几个说明:
1.加入源点,汇点
2.加入每个源点和顾客连线的话,add(0,x,1,0)
3:问题在于怎么在顾客和技术工人上连线:
首先 我们知道 每个顾客可以和每个工人练一天cost(i,j)的线,但是有等待时间
枚举等待时间即是在连接k*cost(i,j)的边,
但是我们不是顾客连一个工人连N条线,工人再连线到汇点,因为我们知道一个工人只能做1个k*cost(i,j),举例来说 比如x这个技术工人只能第一下连y,第二下连z;
所以一个巧妙的思路是:形成n+1 - n*m+n个新点,让1-n 个顾客 与这些点连。(其实一时半会说不出)
总而言之,我们要做到 第一个顾客选择了弟i个技术工人的话 当且仅当联系一次。
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<string> #include<cstdlib> #include<vector> #include<queue> #include<map> #define N 100000 #define inf 0x3f3f3f using namespace std; struct edge { int v,next,flow,cost,cap; }e[N<<2]; int head[N],tot; int pre[N],dis[N]; int vis[N]; int n,m; int cnt; void init() { tot=0; memset(head,-1,sizeof(head)); } void add(int u,int v,int cap,int cost) { e[tot].v=v; e[tot].cap=cap; e[tot].cost=cost; e[tot].flow=0; e[tot].next=head[u];; head[u]=tot++; e[tot].v=u; e[tot].cap=0; e[tot].cost=-cost; e[tot].flow=0; e[tot].next=head[v]; head[v]=tot++; } int spfa(int s,int t) { queue<int>q; for (int i=0;i<=cnt;i++) { dis[i]=inf; vis[i]=0; pre[i]=-1; } dis[s]=0; vis[s]=1; q.push(s); while (!q.empty()) { int u=q.front(); q.pop(); vis[u]=0; for (int i=head[u];i!=-1;i=e[i].next) { int v=e[i].v; if (e[i].cap>e[i].flow&&dis[v]>dis[u]+e[i].cost) { dis[v]=dis[u]+e[i].cost; pre[v]=i; if (!vis[v]) { vis[v]=1; q.push(v); } } } } return pre[t]!=-1; } int minCost(int s,int t,int &cost) { int flow=0; cost=0; while (spfa(s,t)) { int Min=inf; for (int i=pre[t];i!=-1;i=pre[e[i^1].v]) Min=min(Min,e[i].cap-e[i].flow); for (int i=pre[t];i!=-1;i=pre[e[i^1].v]) { e[i].flow+=Min; e[i^1].flow-=Min; cost+=e[i].cost*Min; } flow+=Min; } return flow; } int mp[123][123]; int main() { init(); scanf("%d%d",&m,&n); int s=0; for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) scanf("%d",&mp[i][j]); for (int i=1;i<=n;i++) add(s,i,1,0); cnt=n; for (int i=1;i<=m;i++)//主要是这里 for (int k=1;k<=n;k++) { ++cnt; for (int j=1;j<=n;j++) add(j,cnt,1,k*mp[j][i]); } for (int i=n+1;i<=cnt;i++) add(i,cnt+1,1,0); cnt++; int t=cnt; int ans; int flow=minCost(s,t,ans); //printf("%d\n",ans); printf("%.2lf\n",(double) ans/n); return 0; }
随性Code