您的位置:首页 > 其它

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
由以上四类边,求最小费用流即可。
比如第二组样例的图示:




小结:分析出合理的流向,和费用,注意流量的限制。合理建图。
]// 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: