lightoj 1243 - Guardian Knights(费用流)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_37943488/article/details/82258701


1243 - Guardian Knights

    PDF (English) Statistics Forum
Time Limit: 2 second(s) Memory Limit: 32 MB

The kingdom of Azkaroth is in great danger. Some strange creatures have captured the city and attacking the poor inhabitants.

The old wise king has chosen his best knights to save the kingdom from these creatures. They have already found that the creatures are targeting some food mills. So, the best way is to send the knights to look after the food mills. And if anything goes wrong he may call others to attack the creatures.

The kingdom can be modeled as an n x n grid. The legends are:

'#'       denotes a rock

'.'         denotes an empty space

[A-Z]  denotes a knight

'm'      denotes a mill

A knight can go to a mill using some moves, in each move a knight can go to its four neighboring cells {North, East, West, South} with the restriction that the destination cell shouldn't contain a rock (multiple knights can move together in a cell). And the number of mills that can be maintained by a knight is limited. The cost to look after a mill by a knight is the distance between the knight and the mill, distance means the number of moves the knight has to use to go to the mill. If a knight looks after multiple mills, the cost is the summation of distances from the knight to the mills.

Now your task is to find the minimum total cost needed for the knights to look after all the mills. There can be more than one knight looking after a mill.

Input

Input starts with an integer T (≤ 100), denoting the number of test cases.

Each case starts with a line containing three integers n (5 ≤ n ≤ 30)k (1 ≤ k ≤ 26) and m (1 ≤ m ≤ 100) where k denotes the number of knights and m denotes the number of mills in the grid. The knights will be marked by first k capital letters and the grid contains exactly one letter of each kind. Each of the next n lines contains n characters denoting the grid. The next line contains k space separated integers (between 1 and 100) denoting the number of mills the ith knight can look after. That means the first integer denotes the number of mills that can be looked after by knight 'A', second integer denotes the number of mills looked after by knight 'B' and so on. And the outer cells of the grid will be rocks.

Output

For each case, print the case number and the minimum cost as described above. You can assume that a solution will always exist.

Sample Input

Output for Sample Input

2

7 4 5

#######

#A..mD#

#....m#

#..m.m#

#....m#

#B...C#

#######

1 2 1 1

7 3 6

#######

#A#.m.#

#.#..m#

#m#m.m#

##...m#

#B...C#

#######

1 2 3

Case 1: 15

Case 2: 19

 题目大意:一个n*n的地图,k个骑士,m个磨坊,一个骑士可以保护多个磨坊,一个磨坊可以被多个骑士保护,每个骑士保护磨坊对应的花费是该骑士到该磨坊的距离,问最少花费

一开始总是想着拆点,写了老半天也没写对,看了眼别人的题解才发现不用拆点,我想大概是因为没有限制吧,很多拆点的题目都是要求某个点只能走一遍什么的。对于这道题,直接连边,源点向骑士连边,费用为0,容量为该骑士能保护的磨坊数量,每个磨坊向汇点连边,容量为1,费用为0,每个磨坊一个骑士来保护就够了,多了的话反而增加花费,然后对图进行遍历,每次遇到骑士,就进行bfs,求出该骑士与每个磨坊的距离,建一条容量为1,费用为距离的边。最后跑一遍费用流即可

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=400;
const int maxm=10010;
const int inf=0x3f3f3f3f;
typedef pair<int,int> P;
struct Node
{
    int to;
    int capa;
    int cost;
    int next;
}edge[maxm];
int n,k,m;
int cnt;
int source,sink;
int head[maxn];
char map[maxn][maxn];
int dis[maxn];
bool vis[maxn];
int pre[maxn];
int rec[maxn];
int num[maxn];
bool vis_map[maxn][maxn];
int diss[maxn][maxn];
int dirx[]={0,1,0,-1};
int diry[]={1,0,-1,0};
int mill[50][50];
void init()
{
	cnt=0;
	memset(head,-1,sizeof(head));
	return;
}
void add(int u,int v,int capa,int cost)
{
	edge[cnt].to=v;
	edge[cnt].capa=capa;
	edge[cnt].cost=cost;
	edge[cnt].next=head[u];
	head[u]=cnt++;
	edge[cnt].to=u;
	edge[cnt].capa=0;
	edge[cnt].cost=-cost;
	edge[cnt].next=head[v];
	head[v]=cnt++;
	return;
}
bool spfa()
{
	queue<int> que;
	que.push(source);
	memset(dis,inf,sizeof(dis));
	memset(vis,false,sizeof(vis));
	memset(rec,-1,sizeof(rec));
	memset(pre,-1,sizeof(pre));
	dis[source]=0;
	vis[source]=true;
	while(!que.empty())
	{
		int node=que.front();
		que.pop();
		vis[node]=false;
		for(int i=head[node];~i;i=edge[i].next)
		{
			int v=edge[i].to;
			if(edge[i].capa>0&&dis[v]>dis[node]+edge[i].cost)
			{
				dis[v]=dis[node]+edge[i].cost;
				rec[v]=i;
				pre[v]=node;
				if(!vis[v])
				{
					vis[v]=true;
					que.push(v);
				}
			}
		}
	}
	return dis[sink]!=inf;
}
int mcmf()
{
	int mincost=0;
	while(spfa())
	{
		int node=sink;
		int flow=inf;
		while(node!=source)
		{
			flow=min(flow,edge[rec[node]].capa);
			node=pre[node];
		}
		node=sink;
		while(node!=source)
		{
			mincost+=flow*edge[rec[node]].cost;
			edge[rec[node]].capa-=flow;
			edge[rec[node]^1].capa+=flow;
			node=pre[node];
		}
	}
	return mincost;
}
int getIndex(int x,int y)
{
    return (x-1)*n+y;
}
void bfs(int x,int y)
{
    queue<P> que;
    que.push(make_pair(x,y));
    memset(vis_map,false,sizeof(vis_map));
    diss[x][y]=0;
    while(!que.empty())
    {
        P now=que.front();
        que.pop();
        int tmpx=now.first;
        int tmpy=now.second;
        for(int i=0;i<4;i++)
        {
            int nx=tmpx+dirx[i];
            int ny=tmpy+diry[i];
            if(nx>=1&&nx<=n&&ny>=1&&ny<=n&&!vis_map[nx][ny]&&map[nx][ny]!='#')
            {
                que.push(make_pair(nx,ny));
                vis_map[nx][ny]=true;
                diss[nx][ny]=diss[tmpx][tmpy]+1;
                if(map[nx][ny]=='m')
                {
                    add(map[x][y]-'A'+1,mill[nx][ny]+k,1,diss[nx][ny]);
                }
            }
        }
    }
    return;
}
int main()
{
	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
    int test;
    scanf("%d",&test);
    for(int cas=1;cas<=test;cas++)
    {
		init();
        scanf("%d%d%d",&n,&k,&m);
        getchar();
        source=0;
        sink=k+m+1;
        for(int i=1;i<=n;i++)
        {
            scanf("%s",map[i]);
        }
        for(int i=1;i<=k;i++)
        {
            scanf("%d",&num[i]);
            add(source,i,num[i],0);
        }
        for(int i=1;i<=m;i++)
        {
            add(k+i,sink,1,0);
        }
        int mill_index=1;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(map[i][j]=='m')
                {
                    mill[i][j]=mill_index++;
                }
            }
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(map[i][j]>='A'&&map[i][j]<='Z')
                {
                    bfs(i,j);
                }
            }
        }
        printf("Case %d: %d\n",cas,mcmf());
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37943488/article/details/82258701
今日推荐