HDU-4370___0 or 1 —— 最小花费环 + 神级思维

题目链接:点我啊╭(╯^╰)╮
夜已深、金庸先生走了、、感觉这是我们失去的时代…

题目大意:

    给出一个 n ∗ n n*n nn的矩阵 C C C,要找出一个 n ∗ n n*n nn 01 0 1 01矩阵 X X X,使得 Σ C i j ∗ X i j ΣC_{ij}*X_{ij} ΣCijXij最小??
    矩阵 X X X满足下面几个条件:

  1. X 12 + X 13 + . . . + X 1 n = 1 X_{12}+X_{13}+... + X_{1n}=1 X12+X13+...+X1n=1
  2. X 1 n + X 2 n + . . . + X n − 1 n = 1 X_{1n}+X_{2n}+... +X_{n-1n}=1 X1n+X2n+...+Xn1n=1
  3. 对每个 i ( 1 < i < n ) i (1<i<n) i(1<i<n), 满足 ∑ X k i ( 1 < = k < = n ) = ∑ X i j ( 1 < = j < = n ) . ∑X_{ki} (1<=k<=n)=∑X_{ij} (1<=j<=n). Xki(1<=k<=n)=Xij(1<=j<=n).

解题思路:

    题目很诡异,如果不放在最短路的章节里,估计一般人想不到用最短路来做,我也是看了别人的思路才懂。。。
    既然大家都喜欢看别人的思路的话,那我也来整理一下我的想法吧
    既然是用最短路的思想来解决,那么我们首先就得找出虚拟出最短路的条件:点、边
    首先,先虚拟出 n n n个点,如果题目做多了话,可以想象这 n n n个点和上面的矩阵相对应,那么接下来就是处理边的问题了,这里就需要抽象的理解题目给的三个条件:

  1. X 12 + X 13 + . . . + X 1 n = 1 X_{12}+X_{13}+... + X_{1n}=1 X12+X13+...+X1n=1 1 1 1的出度为 1 1 1
  2. X 1 n + X 2 n + . . . + X n − 1 n = 1 X_{1n}+X_{2n}+... +X_{n-1n}=1 X1n+X2n+...+Xn1n=1 n n n的入度为 1 1 1
  3. 对每个 i ( 1 < i < n ) i (1<i<n) i(1<i<n), 满足 ∑ X k i ( 1 < = k < = n ) = ∑ X i j ( 1 < = j < = n ) . ∑X_{ki} (1<=k<=n)=∑X_{ij} (1<=j<=n). Xki(1<=k<=n)=Xij(1<=j<=n). 2 2 2 ~ n − 1 n-1 n1的入度和出度相同

    如果能理解上面三个抽象的理解,那么转化为最短路也就更加容易抽象理解了,当然,如果你不能理解的话,emmm,那就多看几遍吧。。

    点 1 1 1的出度为 1 1 1即代表这张图由 1 1 1出发
    点 n n n的入度为 1 1 1即代表这张图的终点为 n n n
    点 2 2 2 ~ n − 1 n-1 n1的入度和出度相同:这张图中途可能经过点 2 2 2 ~ n − 1 n-1 n1,也就是一个完整的最短路了,从1跑到n求最短路径

    当然,题目的精妙之处还在于,如果从点 1 1 1出发,跑了一个圈(至少经过一个点)又回到了 1 1 1,然后从 n n n出发,跑了一个圈(至少经过一个点)又回到了 n n n,会发现也是满足题意的,不信你可以对照要求
    那么我们就还要求点 1 1 1和点 n n n的最小花费环,具体求法之间看代码就行了,答案为 m i n ( d i s [ n ] , l o o p 1 + l o o p n ) min(dis[n], loop_1 + loop_n) mindis[n],loop1+loopn

代码思路:

    用哪套最短路模板都行, n n n只有 300 300 300

核心:看似是数学题,实则是谁也想不到

#include<bits/stdc++.h>
using namespace std;

const int INF = 0x3F3F3F3F;
const int N = 1005;
int m, n, st, mp[N][N];
int dis[N], vis[N];

void creatgraph() {
	int t1, t2, t3;
	for (int i=1; i<=n; i++)
		for (int j=1; j<=n; j++)
			scanf("%d", &mp[i][j]);
}

void dijkstra(int st) {
	memset(vis, 0, sizeof(vis));
	for (int i=1; i<=n; i++) dis[i] = mp[st][i];
	dis[st] = INF;
	for (int i=1; i<=n; i++) {
		/*找出离起点最近的点*/
		int minn = INF, k = -1;
		for (int j=1; j<=n; j++) {
			if (!vis[j] && dis[j]<minn) {
				minn = dis[j];
				k = j;
			}
		}
		if(k==-1) break;
		vis[k] = 1;
		for (int j=1; j<=n; j++) {	//松弛操作,找到媒介使得出现新的最短路
			if (!vis[j] && dis[k]+mp[k][j] < dis[j])
				dis[j] = dis[k] + mp[k][j];
		}
	}
}

int main() {
	while(~scanf("%d", &n)) {
		creatgraph();	//建图
		dijkstra(1);
		int ans = dis[n];
		int loop1 = dis[1];
		dijkstra(n);
		int loop2 = dis[n];
		ans = min(ans, loop1+loop2);
		printf("%d\n", ans);
	}
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值