P2053 [SCOI2007]修车
题目描述
同一时刻有N位车主带着他们的爱车来到了汽车维修中心。维修中心共有M位技术人员,不同的技术人员对不同的车进行维修所用的时间是不同的。现在需要安排这M位技术人员所维修的车及顺序,使得顾客平均等待的时间最小。
说明:顾客的等待时间是指从他把车送至维修中心到维修完毕所用的时间。
输入输出格式
输入格式:
第一行有两个数M,N,表示技术人员数与顾客数。
接下来n行,每行m个整数。第i+1行第j个数表示第j位技术人员维修第i辆车需要用的时间T。
输出格式:
最小平均等待时间,答案精确到小数点后2位。
输入输出样例
说明
(2<=M<=9,1<=N<=60), (1<=T<=1000)
这是网络流?
这是网络流???
这不是那种随便贪一贪就能出来的题吗?
以上是看题解前的全部想法
一道思路很神奇的最小费用流
设第i辆车交给第j个人修的耗时是a[i][j]
把每个工人拆成n个点,分别代表他修的倒数第1~n辆车(每个人最多修n辆车嘛)
于是一共有n*m个工人点
如果第i辆车是第j个工人倒数第k辆修的车的话,那么这个人以及这个工人接下来要修的那些车的主人都要等a[i][j]的时间,总的贡献就是a[i][j]*k
于是从第i辆车到第[j][k]个工人点连一条流量1费用k*a[i][j]的边
最后再建立超级源汇,跑最小费用流就好了
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int N=1000,M=N*N,inf=1e9+7; int n,m,a[N][N],id[N][N],cnt=1,p[M],tot,s,t; int dis[M]; bool vis[M],in[M]; queue<int>q; struct edge{int to,nex,val,cos;}e[M<<1]; void add(int u,int v,int lim,int cos){ e[++cnt]=(edge){v,p[u],lim,cos}; p[u]=cnt; e[++cnt]=(edge){u,p[v],0,-cos}; p[v]=cnt; } bool spfa(){ for(int i=0;i<M;++i)dis[i]=inf; while(!q.empty())q.pop(); memset(in,0,sizeof in); dis[s]=0;q.push(s); while(!q.empty()){ int x=q.front();q.pop();in[x]=0; for(int i=p[x];i;i=e[i].nex){ int v=e[i].to; if(e[i].val&&dis[v]>dis[x]+e[i].cos){ dis[v]=dis[x]+e[i].cos; if(!in[v]){q.push(v);in[v]=1;} } } } return dis[t]<inf; } int dfs(int x,int li){ vis[x]=1; if(x==t)return li; int use=li; for(int i=p[x];i;i=e[i].nex){ int v=e[i].to; if(!vis[v]&&e[i].val&&use&&dis[v]==dis[x]+e[i].cos){ int re=dfs(v,min(use,e[i].val)); use-=re; e[i].val-=re; e[i^1].val+=re; } } return li-use; } int dinic(){ int ans=0; while(spfa()){ memset(vis,0,sizeof(vis)); ans+=dfs(s,inf)*dis[t]; // cout<<ans<<endl; } return ans; } int main(){ scanf("%d%d",&m,&n);//技术人员数和顾客数 tot=n; for(int i=1;i<=n;++i) for(int j=1;j<=m;++j){ scanf("%d",&a[i][j]);//第i辆车第m个人修耗时 id[j][i]=++tot; }t=++tot; for(int i=1;i<=n;++i)//第i辆车 for(int j=1;j<=m;++j)//第m个人 for(int k=1;k<=n;++k)//倒数第k个修 add(i,id[j][k],1,k*a[i][j]); for(int i=1;i<=n;++i) add(s,i,1,0); for(int j=1;j<=m;++j) for(int k=1;k<=n;++k) {add(id[j][k],t,1,0);} double ave=dinic(); ave/=n; printf("%.2f",ave); return 0; }
by:wypx
fuck,我去你个垃圾题目,毁我青春。害的我作业没写完
不就是一个最小费用流,吧一个人变成m个,在把m个分别连上汇点.每一个车连人拆出来的m个点,费用分别是k*t。
t是花费时间。
#include<iostream> #include<cstdio> #include<algorithm> #include<cstdlib> #include<cstring> #include<vector> #include<queue> #define ll long long using namespace std; const int INT=1e7; const int maxn=4000; inline int read(){ int an=0; char ch=getchar(); while(‘9‘<ch||ch<‘0‘){ch=getchar();} while(ch<=‘9‘&&‘0‘<=ch){an=an*10+(ch^48);ch=getchar();} return an; } double ANS; int f[40000],id[100][100],cnt=1,S,T,cntt,n,m; int map[100][100],car_id[100]; struct saber{ int nex,to,wi,lim; }b[maxn*maxn]; inline void add2(int x,int y,int z,int wi){ cnt++; b[cnt].nex=f[x]; b[cnt].to=y; b[cnt].wi=wi; b[cnt].lim=z; f[x]=cnt; } inline void add(int x,int y,int z,int wi){ add2(x,y,z,wi); add2(y,x,0,-wi); } inline void prepare(){ m=read();n=read();//m个mmp的工人,闲着没事儿去~~修~~ (开)n个车 for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)cntt++,id[i][j]=cntt; for(int j=1;j<=n;j++)cntt++,car_id[j]=cntt; cntt++;S=cntt; cntt++;T=cntt; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)map[i] [j]=read();//前是车号,后是人修 for(int i=1;i<=n;i++)//n车 for(int j=1;j<=m;j++) for(int k=1;k<=n;k++) add( car_id[i] , id[k][j] ,1, k*map [i] [j] ); for(int i=1;i<=n;i++)add(S,car_id[i],1,0); for(int i=1;i<=n;i++)//n车 for(int j=1;j<=m;j++)add(id[i][j],T,1,0); } deque<int>q; int dis[maxn]; bool in[maxn],vis[maxn]; inline int bfs(){ while(!q.empty())q.pop_back(); for(int i=0;i<=cntt+233;i++)dis[i]=INT; dis[S]=0;q.push_back(S); memset(in,0,sizeof in); while(!q.empty()){ int x=q.front();q.pop_front();in[x]=0; for(int i=f[x];i;i=b[i].nex){ int v=b[i].to; if(dis[v]>dis[x]+b[i].wi&&b[i].lim){ dis[v]=dis[x]+b[i].wi; if(!in[v]){ in[v]=1; if(!q.empty()&&dis[q.front()]>dis[v])q.push_front(v); else q.push_back(v); } } } } return dis[T]!=INT; } inline int dfs(int x,int li){ int used=li;vis[x]=1; if(x==T||!li)return li; for(int i=f[x];i&&used;i=b[i].nex){ int v=b[i].to; if(vis[v])continue; if(dis[v]==dis[x]+b[i].wi&&b[i].lim){ int re=dfs(v,min(used,b[i].lim)); used-=re; b[i^1].lim+=re; b[i].lim-=re; } } return li-used; } inline void dinic(){ int ans=0; while(bfs()){ memset(vis,0,sizeof vis); ans+=dis[T]*dfs(S,INT); } ANS=(double)ans/(double)n; printf("%0.2f",ANS); } int main(){ prepare(); dinic(); return 0; }
by:s_a_b_e_r