HDU 4370 0 or 1
好像是多校的题,这题出的确实好,加深了我对图和最短路更本质的理解
乍一看是个01规划?毕竟学校有学运筹学hhh
一开始很蒙啊,到处看题解博客,博客真的是各种理解,最后回到出度和入度上
个人感觉逻辑都不是很通顺,直到看了kuangbin的博客之后才比较清晰
我们回到刚开始学习图论的时候,如何存图?
答:邻接矩阵
邻接矩阵中的每个元素是什么意思?
答:如果是无权图,G(i,j)=1,代表有i到j的一条边
如果是带权图则表示这条边的权值
我们再来看这道题
我们完全可以把矩阵X看成一个描述无权图连接情况的邻接矩阵
这就是为什么我们最后会把题目给的三个条件与出入度相结合的原因了
那么我们要求的最小值又是什么呢?
如果把题目中的C看成是图的完全邻接矩阵,那么∑C(i,j)X(i,j)可以看成是一个对C的函数,f(C),当函数作用于C,即作用于一个完全图的时候,就是让我们求原图中的路径,这个路径满足点1的出度为1,点n的入度为1,其他点的出入度相等。
这种路径的本质又是什么呢,一条从1到n的最短路显然满足这种条件,但这最短路是他的充分条件却不必要,因为最短路还满足点1的入度为0,点n的出度为1,于是我们考虑经过1的最小环和经过n的最小环,由于要保证1的出度为1,n的入度为1,那么这两个自环都必须是至少经过了一个其他点的环。
综上,这个题归结为
求1到n的最短路,两个最小环 之间的最小值
//神仙题目
//乍一看 01规划
//必然不可能直接解
//而且肯定是多解
//就算是考虑图 也一般会往网络流上想 但想了十分钟网络流行不通
//是在不知道怎么用最短路。。。
//很多博客也是说不清楚就乱说啊。。。
//看了kuangbin的题解才比较显然:为什么要把矩阵X的行列关系看成出度和入度?
//因为如果 把C看成邻接矩阵 从1到n的一条最短路必能能满足矩阵X中的要求 显然源点的出度为1 终点入度为1 其他点入度等于出度
//但充分不必要
//直到考虑了包括1的环 和包括n的环 后才是充要条件
//但不能是自环 因为矩阵X要求1有出度且n有入度
//其实看开点想 会有很大收获
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int INF = 1<<25;
int n;
int g[305][305];
int vis[305],d[305];
void spfa(int s)
{
queue<int>q;
for(int i=1;i<=n;i++)
{
if(i!=s)
{
q.push(i);
d[i] = g[s][i];
vis[i] = 1;
}
else
{
d[i] = INF;
vis[i] = 0;
}
}
while(!q.empty())
{
int u = q.front();q.pop();
vis[u] = 0;
for(int v=1;v<=n;v++)
{
if(d[v]>d[u]+g[u][v])
{
d[v] = d[u]+g[u][v];
if(!vis[v])
{
q.push(v);
vis[v] = 1;
}
}
}
}
}
int main()
{
while(~scanf("%d",&n))
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++) scanf("%d",&g[i][j]);
}
spfa(1);
int ans = d[n];
int loop1 = d[1];
spfa(n);
int loop2 = d[n];
ans = min(ans,loop1+loop2);
printf("%d\n",ans);
}
return 0;
}
其实自己想的时候浮想联翩,感慨万千
但是写出来感觉意味差了很多。。。
零碎的补充一点自己的感慨把:
1、不要忘了邻接矩阵本质就是用来表示两点相连情况的
2、一个图我们可以用矩阵约束,并构造目标函数,使得求解一些最小值看起来像是在求线性规划
*比如哈密顿路径问题:
构造目标函数 min w = ∑G(i,j)X(i,j)
约束条件
∑X(1,j) = 1 点1的出度为1
∑X(j,n) = 1 点n的入度为1
∑X(k,j) = ∑X(j,k) = 1 k=2,3,…,n-1 其他点的出度和入度都为1
X(i,j) = 0或1
这就把哈密顿路径转化成了一个指派问题
但其实还有些不足,因为这样的约束没有避免这条路成环,如果能用约束条件解决这个问题,那么就可以很直观的用01规划来表示图论的一些求解模型