POJ 2516 최소 비용 KM 알고리즘 또는 최소 비용 최대 흐름
7478 단어 알고리즘
당연히 팁 을 쓰 는 것 이 가장 편리 하 다.건축 도 는 일목요연 하 다.
KM 번 거 로 움 은 모든 물건 을 하나씩 뜯 어야 한 다 는 것 이다.
그림 을 만 들 때 KM 가 일치 하 는 템 플 릿 은 왼쪽 의 포인트 가 오른쪽 포인트 보다 크 지 않 음 을 주의 하 십시오. 적어도 제 템 플 릿 은 이 렇 습 니 다.
본 문제 에서 공급 업 체 가 제공 하 는 물건 은 상점 의 수 요 를 만족 시 키 고 만족 하지 못 하면 직접 수출 해 야 한다. - 1. 따라서 이론 적 으로 상점 의 점 은 공급 업 체 보다 적 고 상점 의 점 은 왼쪽 에 두 어야 하 며 공급 업 체 는 오른쪽 에 두 어야 한다.
최소 권 이 일치 하기 때문에 나 는 여기 서 비교적 큰 수 에서 가중치 를 빼 서 처리 하 는 것 이지 직접 마이너스 수 를 취 하 는 것 이 아니다.
먼저 팁 입 니 다.
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <cstdio>
#include <cmath>
#include <queue>
#include <map>
#include <set>
#define eps 1e-5
#define MAXN 111
#define MAXM 55555
#define INF 100000007
using namespace std;
struct EDGE
{
int v, cap, cost, next, re; // re 。
} edge[MAXM];
int n, m, ans, flow, src, des;
int e, head[MAXN];
int que[MAXN], pre[MAXN], dis[MAXN];
bool vis[MAXN];
void init()
{
e = ans = flow = 0;
memset(head, -1, sizeof(head));
}
void add(int u, int v, int cap, int cost)
{
edge[e].v = v;
edge[e].cap = cap;
edge[e].cost = cost;
edge[e].next = head[u];
edge[e].re = e + 1;
head[u] = e++;
edge[e].v = u;
edge[e].cap = 0;
edge[e].cost = -cost;
edge[e].next = head[v];
edge[e].re = e - 1;
head[v] = e++;
}
bool spfa()
{
int i, h = 0, t = 1;
for(i = 0; i <= n; i ++)
{
dis[i] = INF;
vis[i] = false;
}
dis[src] = 0;
que[0] = src;
vis[src] = true;
while(t != h)
{
int u = que[h++];
h %= n;
vis[u] = false;
for(i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].v;
if(edge[i].cap && dis[v] > dis[u] + edge[i].cost)
{
dis[v] = dis[u] + edge[i].cost;
pre[v] = i;
if(!vis[v])
{
vis[v] = true;
que[t++] = v;
t %= n;
}
}
}
}
if(dis[des] == INF) return false;
return true;
}
void end()
{
int u, p, mi = INF;
for(u = des; u != src; u = edge[edge[p].re].v)
{
p = pre[u];
mi = min(mi, edge[p].cap);
}
for(u = des; u != src; u = edge[edge[p].re].v)
{
p = pre[u];
edge[p].cap -= mi;
edge[edge[p].re].cap += mi;
ans += mi * edge[p].cost; // cost , 。
}
flow += mi;
}
int nt, k;
int shop[55][55], sup[55][55];
int money;
int main()
{
while(scanf("%d%d%d", &nt, &m, &k) != EOF)
{
if(!nt && !m && !k) break;
int res = 0;
n = nt + m + 2;
src = nt + m + 1;
des = nt + m + 2;
for(int i = 1; i <= nt; i++)
for(int j = 1; j <= k; j++)
scanf("%d", &shop[i][j]);
for(int i = 1; i <= m; i++)
for(int j = 1; j <= k; j++)
scanf("%d", &sup[i][j]);
int flag = 1;
for(int q = 1; q <= k; q++)
{
init();
for(int i = 1; i <= nt; i++)
for(int j = 1; j <= m; j++)
{
scanf("%d", &money);
add(j, i + m, INF, money);
}
int fk = 0;
for(int i = 1; i <= m; i++)
add(src, i, sup[i][q], 0);
for(int i = 1; i <= nt; i++)
add(i + m, des, shop[i][q], 0), fk += shop[i][q];
while(spfa()) end();
res += ans;
if(flow != fk) flag = 0;
}
if(flag)
printf("%d
", res);
else printf("-1
");
}
return 0;
}
그리고 KM 으로 했 어 요.
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <cstdio>
#include <cmath>
#include <queue>
#include <map>
#include <set>
#define eps 1e-5
#define MAXN 555
#define MAXM 55555
#define INF 100000007
using namespace std;
int n, m, ny, nx;
int w[MAXN][MAXN];
int lx[MAXN], ly[MAXN];
int linky[MAXN];
int visx[MAXN], visy[MAXN];
int slack[MAXN];
bool find(int x)
{
visx[x] = 1;
for(int y = 1; y <= ny; y++)
{
if(visy[y]) continue;
int t = lx[x] + ly[y] - w[x][y];
if(t == 0)
{
visy[y] = 1;
if(linky[y] == -1 || find(linky[y]))
{
linky[y] = x;
return true;
}
}
else if(slack[y] > t) slack[y] = t;
}
return false;
}
int KM()
{
memset(linky, -1, sizeof(linky));
for(int i = 1; i <= nx; i++) lx[i] = -INF;
memset(ly, 0, sizeof(ly));
for(int i = 1; i <= nx; i++)
for(int j = 1; j <= ny; j++)
if(w[i][j] > lx[i]) lx[i] = w[i][j];
for(int x = 1; x <= nx; x++)
{
for(int i = 1; i <= ny; i++) slack[i] = INF;
while(true)
{
memset(visx, 0, sizeof(visx));
memset(visy, 0, sizeof(visy));
if(find(x)) break;
int d = INF;
for(int i = 1; i <= ny; i++)
if(!visy[i]) d = min(d, slack[i]);
if(d == INF) return -1;
for(int i = 1; i <= nx; i++)
if(visx[i]) lx[i] -=d;
for(int i = 1; i <= ny; i++)
if(visy[i]) ly[i] += d;
else slack[i] -= d;
}
}
int cnt = 0;
for(int i = 1; i <= ny; i++)
if(linky[i] != -1) cnt++;
if(cnt != nx) return -1;
int tp = 0;
for(int i = 1; i <= ny; i++)
if(linky[i] != -1 ) tp += w[linky[i]][i] - 200;
return -tp;
}
int nt, k;
int shop[55][55], sup[55][55];
int money[55][55];
int ha[555], hb[555];
int main()
{
while(scanf("%d%d%d", &nt, &m, &k) != EOF)
{
if(!nt && !m && !k) break;
for(int i = 1; i <= nt; i++)
for(int j = 1; j <= k; j++)
scanf("%d", &shop[i][j]);
for(int i = 1; i <= m; i++)
for(int j = 1; j <= k; j++)
scanf("%d", &sup[i][j]);
int flag = 1, res = 0;
for(int q = 1; q <= k; q++)
{
memset(w, 0, sizeof(w));
for(int i = 1; i <= nt; i++)
for(int j = 1; j <= m; j++)
scanf("%d", &money[i][j]);
nx = 0, ny = 0;
for(int i = 1; i <= nt; i++)
for(int j = 1; j <= shop[i][q]; j++)
{
nx++;
ha[nx] = i;
}
for(int i = 1; i <= m; i++)
for(int j = 1; j <= sup[i][q]; j++)
{
ny++;
hb[ny] = i;
}
for(int i = 1; i <= nx; i++)
for(int j = 1; j <= ny; j++)
w[i][j] = 200 - money[ha[i]][hb[j]];
int tp = KM();
if(tp == -1) flag= 0;
else res += tp;
}
if(flag)
printf("%d
", res);
else printf("-1
");
}
return 0;
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
물체 검출의 평가 지표 IoU의 계산 방법Yolo나 SSD 등 물체 검출에서 평가 지표로 사용되는 IoU에 대해 조사했으므로 정리했습니다. IoU (Intersection over Union)는 두 영역이 얼마나 겹치는지를 나타내는 지표입니다. 두 영역의 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.