描述
题解
用最小割做是要死人的,看了周冬前辈中学时的论文,搞清楚了这种题要转化为最短路搞,不过建起图来是一个恶心人的事情~~~
具体论文参见:浅析最大最小定理在信息学竞赛中的应用
代码
#include <iostream>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
const int MAXN = 170000;
const int INF = 0x3f3f3f3f;
struct point
{
int v, w;
} Point;
vector<point> Edge[MAXN];
int n,S,T,q[MAXN];
int dist[MAXN];
bool inq[MAXN];
int SPFA()
{
int head = 0, tail = 0;
memset(inq, false, sizeof(inq));
for (int i = 0; i <= (n - 1) * (n - 1) + 1; i++)
{
dist[i] = INF;
}
q[tail++] = S;
dist[S] = 0;
inq[S] = true;
while (head != tail)
{
int k = q[head];
head = (head + 1) % MAXN;
inq[k] = false;
for (int i = 0; i < Edge[k].size(); i++)
{
Point = Edge[k][i];
if (dist[Point.v] > dist[k] + Point.w)
{
dist[Point.v] = dist[k] + Point.w;
if (!inq[Point.v])
{
inq[Point.v] = true;
q[tail] = Point.v;
tail = (tail + 1) % MAXN;
}
}
}
}
return dist[T];
}
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
scanf("%d", &n);
for (int i = 0; i < (n - 1) * (n - 1) + 2; i++)
{
Edge[i].clear();
}
S = (n - 1) * (n - 1);
T = (n - 1) * (n - 1) + 1;
int w;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
scanf("%d", &w);
Point.w = w;
if (i == 0 && j != n - 1)
{
Point.v = j;
Edge[S].push_back(Point);
}
else if (j == n - 1 && i != n - 1)
{
Point.v = i * (n - 1) + j - 1;
Edge[S].push_back(Point);
}
if (j == 0 && i != n - 1)
{
Point.v = T;
Edge[i * (n - 1)].push_back(Point);
}
else if (i == n - 1 && j != n - 1)
{
Point.v = T;
Edge[(n - 2) * (n - 1) + j].push_back(Point);
}
if (i != n - 1 && j != n - 1)
{
if (i)
{
Point.v = (i - 1) * (n - 1) + j;
Edge[i * (n - 1) + j].push_back(Point);
Point.v = i * (n - 1) + j;
Edge[(i - 1) * (n - 1) + j].push_back(Point);
}
if (j)
{
Point.v = i * (n - 1) + j - 1;
Edge[i * (n - 1) + j].push_back(Point);
Point.v = i * (n - 1) + j;
Edge[i * (n - 1) + j - 1].push_back(Point);
}
}
}
}
printf("%d\n", SPFA());
}
return 0;
}