图论例题合集(三)(未完成)

A:LightOJ - 1243 Guardian Knights:题目大意:一个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
", cas, mcmf());
	}
	return 0;
}

B:LightOJ - 1198 Karate Competition:题目大意:你的空手道馆要跟别的空手道馆打比赛,每个人都有个技能点,要是技能点比对手的技能点高就加2分,平手加1分,输了不加分。问最多能得多少分 感觉能贪心做,类似于田忌赛马的思路,但是竟然放在了费用流就用费用流做吧..n^2建图,跑费用流即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=1010;
const int maxm=10010;
const int inf=0x3f3f3f3f;
struct Node
{
    int to;
    int capa;
    int cost;
    int next;
}edge[maxm];
int cnt;
int source,sink;
int head[maxn];
int numa[maxn];
int numb[maxn];
int dis[maxn];
bool vis[maxn];
int rec[maxn];
int pre[maxn];
int ldj;
void init()
{
    memset(head,-1,sizeof(head));
    cnt=0;
    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()
{
    memset(vis,false,sizeof(vis));
    memset(dis,inf,sizeof(dis));
    memset(rec,-1,sizeof(rec));
    memset(pre,-1,sizeof(pre));
    queue<int> que;
    que.push(source);
    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 maxflow=0;
    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 main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int test;
    scanf("%d",&test);
    for(int cas=1;cas<=test;cas++)
    {
        init();
        int n;
        scanf("%d",&n);
        source=0;
        sink=n*2+1;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&numa[i]);
        }
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&numb[i]);
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(numa[i]<numb[j])
                {
                    add(i,n+j,1,0);
                }
                else if(numa[i]==numb[j])
                {
                    add(i,n+j,1,-1);
                }
                else 
                {
                    add(i,n+j,1,-2);
                }
            }
        }
        for(int i=1;i<=n;i++)
        {
            add(source,i,1,0);
            add(n+i,sink,1,0);
        }
        printf("Case %d: %d
",cas,mcmf());
    }
    return 0;
}
原文地址:https://www.cnblogs.com/shmilky/p/14089004.html