fzu 1927 取数游戏 【最小费用流】
2010-06-23 09:49
363 查看
fzu 1927 取数游戏
模型有点隐蔽的费用流,很不错的题目。
惭愧的是很长时间没写费用流了,调试了N久。-_-b..
将数组A[i]中的每个数看做一个点i,并拆出对应的点N+i(为了限制流量)。
那么通过这个点的流量可以直接流向汇点,以b[i]的费用。
也可以通过流向其他的点以较小的代价流出。
建图:①新增源点,向每个初始点i连边,容量为1,代价为0;
②新增汇点,由拆分出来的点N+i向汇点连边,容量为1,代价为0;
③由每个初始点i向汇点连边,容量为1,代价为b[i].
④如果A[i],A[j]满足有合适的k,那么由j向N+i连边,容量为1,代价为k+A[j]*k
由以上四类边,求最小费用流即可。
比如第二组样例的图示:
小结:分析出合理的流向,和费用,注意流量的限制。合理建图。
模型有点隐蔽的费用流,很不错的题目。
惭愧的是很长时间没写费用流了,调试了N久。-_-b..
将数组A[i]中的每个数看做一个点i,并拆出对应的点N+i(为了限制流量)。
那么通过这个点的流量可以直接流向汇点,以b[i]的费用。
也可以通过流向其他的点以较小的代价流出。
建图:①新增源点,向每个初始点i连边,容量为1,代价为0;
②新增汇点,由拆分出来的点N+i向汇点连边,容量为1,代价为0;
③由每个初始点i向汇点连边,容量为1,代价为b[i].
④如果A[i],A[j]满足有合适的k,那么由j向N+i连边,容量为1,代价为k+A[j]*k
由以上四类边,求最小费用流即可。
比如第二组样例的图示:
小结:分析出合理的流向,和费用,注意流量的限制。合理建图。
]// fzu 1927 取数游戏 #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<queue> using namespace std; const int MAX=210; const int INF=0x1fffffff; typedef __int64 LL; int N,D,a[MAX],b[MAX]; int TN; int beg,end; int cost[MAX][MAX],g[MAX][MAX],cc[MAX][MAX]; int pre[MAX]; int dist[MAX],mflow[MAX]; bool SPFA() { int i,j,u; memset(pre,-1,sizeof(pre)); queue<int> my; my.push(beg); for(i=0;i<=TN;i++) {dist[i]=INF;mflow[i]=INF;} dist[beg]=0; while(!my.empty()) { u=my.front(); my.pop(); for(i=1;i<=g[u][0];i++) { j=g[u][i]; if(cc[u][j]&&(dist[u]+cost[u][j]<dist[j])) { dist[j]=dist[u]+cost[u][j]; my.push(j); pre[j]=u; mflow[j]=min(mflow[u],cc[u][j]); } } } return (pre[end]!=-1); } int Min_cost_Max_flow() { int ans=0,x; while(SPFA()) { x=end; while(pre[x]>=0) { cc[pre[x]][x]-=mflow[end]; cc[x][pre[x]]+=mflow[end]; x=pre[x]; } ans+=dist[end]*mflow[end]; } return ans; } void init() { int i,j; for(i=0;i<MAX;i++) g[i][0]=0; memset(cc,0,sizeof(cc)); for(i=0;i<=TN;i++) { for(j=0;j<=TN;j++) cost[i][j]=INF; } for(i=1;i<=N;i++) { g[beg][++g[beg][0]]=i; g[i][++g[i][0]]=beg; cc[beg][i]=1; cc[i][beg]=0; cost[beg][i]=0; cost[i][beg]=0; } for(i=N+1;i<=2*N;i++) { g[i][++g[i][0]]=end; g[end][++g[end][0]]=i; cc[end][i]=0; cc[i][end]=1; cost[end][i]=0; cost[i][end]=0; } for(i=1;i<=N;i++) { g[i][++g[i][0]]=end; g[end][++g[end][0]]=i; cc[i][end]=1; cc[end][i]=0; cost[i][end]=b[i]; cost[end][i]=-b[i]; } } LL exp_mod(LL A,LL B,LL M) { bool bit[100]; LL i,k=0,D=1; while(B) { bit[k++]=B&1; B>>=1; } for(i=k-1;i>=0;i--) { D=D*D%M; if(bit[i]) D=D*A%M; } return D; } int mood(int x,int D,int k) { int tt=(int)exp_mod(D,k,N); return (x*tt)%N; } bool ok(int x,int y,int line,int &ddd) { int k=0; for(k=1;k+y*k<line;k++) { if(y==mood(x,D,k)) {ddd=k;return 1;} } return 0; } int main() { int i,j,T;scanf("%d",&T); int CN=0; while(T--) { scanf("%d%d",&N,&D); for(i=1;i<=N;i++) scanf("%d",&a[i]); for(i=1;i<=N;i++) scanf("%d",&b[i]); beg=0;end=2*N+1; TN=2*N+1; init(); int val; for(i=1;i<=N;i++) { for(j=i+1;j<=N;j++) { if(ok(a[i],a[j],b[j],val)) { int x=j,y=N+i; g[x][++g[x][0]]=y; g[y][++g[y][0]]=x; cc[x][y]=1; cc[y][x]=0; cost[x][y]=val+a[j]*val; cost[y][x]=-val-a[j]*val; } } } printf("Case %d: ",++CN); int total=Min_cost_Max_flow(); printf("%d/n",total); } system("pause"); return 0; }
相关文章推荐
- 【CodeVS 1037】取数游戏
- 一个递归实现的取数游戏
- CODEVS_1033 蚯蚓的游戏问题 网络流 最小费用流 拆点
- bzoj 1978: [BeiJing2010]取数游戏 game 数学
- BZOJ 1978: [BeiJing2010]取数游戏 game
- 洛谷 P1123 取数游戏
- Luogu 2469 [SDOI2010]星际竞速 / HYSBZ 1927 [Sdoi2010]星际竞速 (网络流,最小费用流)
- 取数游戏:
- P1288 取数游戏II
- 9265:取数游戏
- CCF NOI100002 取数游戏
- 算法学习——贪心算法之取数游戏(显示两端数字)
- FZU 2135---数字游戏
- FZU1892接水管游戏-BFS加上简单的状态压缩和位运算处理
- FZU 2089 数字游戏
- FZU - 2126 消去游戏 (DP)
- 【区间DP+高精】codevs1166 矩阵取数游戏题解
- 洛谷 P1288 取数游戏II
- FZU 1575 小学生的游戏
- CODEVS_1033 蚯蚓的游戏问题 网络流 最小费用流 拆点