A:LightOJ - 1243 Guardian Knights:题目大意:一个n*n的地图,k个骑士,m个磨坊,一个骑士可以保护多个磨坊,一个磨坊可以被多个骑士保护,每个骑士保护磨坊对应的花费是该骑士到该磨坊的距离,问最少花费 一开始总是想着拆点,写了老半天也没写对,看了眼别人的题解才发现不用拆点,我想大概是因为没有限制吧,很多拆点的题目都是要求某个点只能走一遍什么的。对于这道题,直接连边,源点向骑士连边,费用为0,容量为该骑士能保护的磨坊数量,每个磨坊向汇点连边,容量为1,费用为0,每个磨坊一个骑士来保护就够了,多了的话反而增加花费,然后对图进行遍历,每次遇到骑士,就进行bfs,求出该骑士与每个磨坊的距离,建一条容量为1,费用为距离的边。最后跑一遍费用流即可。
#include
#include
#include
#include
using namespace std;
const int maxn = 400;
const int maxm = 10010;
const int inf = 0x3f3f3f3f;
typedef pair 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 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 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;
}
B:LightOJ - 1198 Karate Competition:题目大意:你的空手道馆要跟别的空手道馆打比赛,每个人都有个技能点,要是技能点比对手的技能点高就加2分,平手加1分,输了不加分。问最多能得多少分 感觉能贪心做,类似于田忌赛马的思路,但是竟然放在了费用流就用费用流做吧..n^2建图,跑费用流即可。
#include
#include
#include
#include
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 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]