[explanation] uva1104 chips challenge

Original question gate

Topic analysis

  • Given an n*n chip.

    '. Indicates that a part can be placed in the grid.

    'C' indicates that a part has been placed in the grid (cannot be removed).

    '/' means that the grid cannot place parts.

    It is required to place as many parts as possible on the existing basis of the chip, so that:

    1. Row i has the same number of parts as column i.
    2. Parts per row and column < = total parts * A/B.

Condition 1

  • Consider how to make the number of parts in row i and column j equal.

    First of all, we can think of the classic row and column bipartite graph model, that is, \ ((i,j) \) if the parts can be placed, then the edges are connected; if the parts must be placed, then the records are required. Finally, run the maximum flow.

    However, the limitation of this model is that it can not control the equality of ranks.

  • We consider using the reverse thinking to solve the problem: if the part can be placed, connect the edges; if the part must be placed, do not connect. The meaning of the edge is that the point \ ((i,j) \) does not place the part.

    What's the advantage of this?

    Since the original edge is a non drop part, we can connect the new edge between \ ((i,i) \) to collect the remaining flow.

    How to understand?

    Set the sum of the parts that can be placed and must be placed in row I to \ (a[i] \), and the flow that has already flowed out of \ (x \) means not selected, the same is true for column I. Then we can use the new edge to collect the remaining flow between \ ((i,i) \), and the flow here means that we choose to place the parts.

    Sample analysis (regardless of condition 2):

    n=2
    C.
    /.
    

    As shown in the figure, the curve between rows and columns represents the original edge not selected, and the line represents the new edge selected.

    At the same time, since (1,1) is' C ', we record its flow and reflect it in the selected edge, but do not create a curve that represents no selection.

    Then the selected maximum flow is 2, and the unselected edge (1,2) flow is 1, that is, the maximum flow = 3.

    The final answer is the selected maximum flow 2 - the existing required flow 1 = 1.

  • By analyzing the solution process of the above example, it is not difficult to find that the maximum flow needs to be run. Check whether the maximum flow equals to the sum of all optional and required flows to determine whether there is a solution (think about why).

    However, the problem is how to control the flow through the straight edge of the collected flow as much as possible?

    It can be seen that among all the largest flows, the one with the largest collection flow should be selected, and the way of adding cost as priority should be considered.

    We make the priority of all the selected edges 1, and the priority of all the unselected edges 0, and the priority reflected in the network flow is the cost.

    In this way, you can run the maximum cost flow. The maximum flow = the total flow of selected and unselected flow, the maximum cost = the total flow of selected flow, and the answer = the maximum cost - the existing required flow.

Condition 2

  • The problem of equal rows and columns is solved, but the problem also requires the flow of each selected side to be less than or equal to the total cost * A/B.

    In other words, we need to limit the current of the new selected edge capacity to make it < = total cost * A/B.

    However, the total cost needs to be calculated after the edge construction, while the total cost needs to be limited. (obviously, the algorithm is locked by condition 2)

    Therefore, we can not wait for the total cost to be calculated passively, but should actively enumerate.

  • Considering the total cost of enumeration, we can find the capacity limit of the selected edge and complete the drawing.

    After running the maximum cost flow, check whether the cost we get is equal to the total cost value enumerated, and update the answer if it is equal to.

    Problem n < = 40, enumerate the total cost complexity \ (n^2 \), how can the cost flow complexity be greater than the maximum flow \ (n\sqrt m==n^2 \), that is to say \ (n^4 \) and \ (n^5 \) complexity is very dangerous in this problem.

  • Consider a common optimization method: keep the residual network from the last enumeration cost, change the capacity limit of the selection side, and then continue to run the cost stream.

    However, this method does not work in this problem. If the capacity limit of the selected edge is + = 1 this time, the current flow of this graph may not be the maximum cost flow before continuing to run the cost flow (think about why). But our spfa+dinic is actually a kind of greedy. We must ensure that the current flow time is the maximum cost flow!

    It may be possible to add a loop elimination algorithm to adjust, but the programming is difficult. We consider changing the enumeration idea directly.

  • When the lim of capacity limit is determined, the total cost we run out will be determined.

    Therefore, it is not necessary to enumerate the total cost at all. We just need to enumerate lim and check whether the total cost meets condition 2.

    That is to say, \ (n \) complexity enumeration capacity limit lim, and then calculate the maximum total cost maxw. As long as \ (lim < = maxw * A / b \) can meet condition 2, update the answer.

    The final answer is the maximum of all possible solutions.

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define fakemain main
#define inf 0x3f3f3f3f
using namespace std;

const int MAXN=110;
int n,s,t,A,B;
char ss[MAXN][MAXN];
int a[MAXN];//Count the total flow of each row and column 
int b[MAXN];//Record the existing traffic of each row and column 

int en=-1,eh[MAXN];
struct edge
{
	int v,c,w,next;
	edge(int V=0,int C=0,int W=0,int N=0):v(V),c(C),w(W),next(N){}
};edge e[MAXN*MAXN];
inline void add_edge(int u,int v,int c,int w)
{
	e[++en]=edge(v,c,w,eh[u]);eh[u]=en;
	e[++en]=edge(u,0,-w,eh[v]);eh[v]=en;
}

void input()
{
	s=n*2+1;t=n*2+2;
	
	memset(a,0,sizeof(a));
	memset(b,0,sizeof(b));
	
	for(int i=1;i<=n;++i)
	{
		scanf("%s",ss[i]+1);
		for(int j=1;j<=n;++j)
		{
			if(ss[i][j]=='C' || ss[i][j]=='.'){++a[i];++a[j+n];}
			if(ss[i][j]=='C'){++b[i];++b[j+n];}
		}
	}
	
	en=-1;
	memset(eh,-1,sizeof(eh));
	
	for(int i=1;i<=n;++i)add_edge(i,i+n,0,-1);//Add optional edge taking, initial capacity is 0 
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j)if(ss[i][j]=='.')//Add no edge selection 
			add_edge(i,j+n,1,0);
	for(int i=1;i<=n;++i)//Add source edge 
	{
		add_edge(s,i,a[i],0);
		add_edge(i+n,t,a[i+n],0);
	}
}

int tota,totb,rstf,lim;//Total flow, total used flow, source flow, optional edge capacity limit 
int maxw,ans;

void init()//Capacity initialization 
{
	for(int i=1;i<=n;++i){e[i*2-2].c=lim;e[i*2-1].c=0;}
	for(int i=n+1;i<=(en+1)/2;++i)
	{
		e[i*2-2].c+=e[i*2-1].c;
		e[i*2-1].c=0;
	}
}

int dis[MAXN],cur[MAXN];
bool inq[MAXN];
bool vis[MAXN];
deque<int> q;
bool spfa()
{
	fill(dis+1,dis+t+1,inf);
	
	dis[s]=0;q.push_back(s);inq[s]=1;
	
	int u,v,w;
	while(!q.empty())
	{
		u=q.front();q.pop_front();inq[u]=0;
		for(int i=eh[u];i!=-1;i=e[i].next)if(e[i].c)
		{
			v=e[i].v;w=e[i].w;
			if(dis[v]>dis[u]+w)
			{
				dis[v]=dis[u]+w;
				if(!inq[v])
				{
					inq[v]=1;
					if(!q.empty() && dis[v]<dis[q.front()])q.push_front(v);
					else q.push_back(v);
				}
			}
		}
	}
	return dis[t]!=inf;
}
int dfs(int u,int flow)
{
	if(u==t)
	{
		maxw+=-dis[t]*flow;
		return flow;
	}
	
	vis[u]=1;
	int v,f,used=0;
	for(int i=cur[u];i!=-1;i=e[i].next)if(e[i].c)
	{
		cur[u]=i;
		v=e[i].v;
		if(dis[u]+e[i].w==dis[v] && !vis[v])
		{
			f=dfs(v,min(flow-used,e[i].c));
			
			e[i].c-=f;
			e[i^1].c+=f;
			
			used+=f;
			if(used==flow)break;
		}
	}
	vis[u]=0;
	return used;
}
void solve()
{
	ans=-inf;tota=0;totb=0;
	for(int i=1;i<=n;++i){tota+=a[i];totb+=b[i];}
	
	for(lim=0;lim<=n;++lim)//Limit lim of enumerating optional edge 
	{
		init();
		rstf=tota;maxw=0;
		while(rstf && spfa())//There is unused traffic and expansion Road 
		{
			memcpy(cur,eh,sizeof(cur));
			rstf-=dfs(s,rstf);
		}
		//If it is exhausted and lim meets heat dissipation, it is feasible solution and the answer is updated 
		if(!rstf && lim<=maxw*A/B)ans=max(ans,maxw-totb);
	}
}

void output()
{
	if(ans==-inf)printf("impossible\n");
	else printf("%d\n",ans);
}

int fakemain()
{
//	freopen("in.txt","r",stdin);
	int cnt=0;
	while(1)
	{
		scanf("%d %d %d",&n,&A,&B);
		if(n==0)return 0;
		printf("Case %d: ",++cnt);
		input();
		solve();
		output();
	}
}

Tags: network less Programming

Posted on Fri, 15 May 2020 03:55:20 -0400 by clodius