列表

详情


NC252370. 厄神降临之路

描述

键山雏有一个 n 个点的简单无向图,点 i 有点权 a_i,点 i 与点 j 之间的连边(如果存在)有边权 e_{ij}定义一条路径的花费是该路径上的点权之和以及边权之和的乘积。
键山雏想要你帮忙找出花费最小的
环。如果你找不着,厄运就到你身上啦!
环是从一个点出发,不经过一条边一次以上,再回到这个点的路径。

输入描述

第一行一个正整数 n
接下来 n 个正整数,第 i 个整数代表点 i 的点权a_i
接下来 n 行,每行 n 个非负整数,第 i 行第 j 列的整数 e_{ij} 代表点 i 与点 j 之间的边权。e_{ij}=0,表示点 i 与点 j 之间的连边不存在。

输出描述

一个正整数表示回路的最小花费,或输出 -1 表示回路不存在。

示例1

输入:

5
2 6 4 9 3
0 0 0 10 4
0 0 0 0 0
0 0 0 3 0
10 0 3 0 0
4 0 0 0 0

输出:

-1

示例2

输入:

5
10 10 10 4 1
0 0 2 5 0
0 0 6 5 7
2 6 0 1 0
5 5 1 0 0
0 7 0 0 0

输出:

192

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

Python3 解法, 执行用时: 44ms, 内存消耗: 4740K, 提交时间: 2023-05-19 20:49:07

n = int(input())
arr = input().strip().split()
from collections import defaultdict
p = {}
for i,num in enumerate(arr):
    p[1<<i] = int(num)

    
road = defaultdict(list)
line = {}
for i in range(n):
    arr = input().strip().split()
    for j,num in enumerate(arr):
        num = int(num)
        if not num:
            continue
            
        road[1<<i].append((1<<j,num))
        line[(1<<i,1<<j)] = num
#         road[1<<j].append((1<<i,num))


visited = set()
global res
res = float("inf")
def dfs(start,cur,level,t1,t2):
    global res
    
    if t1 * t2 >= res:
        return
    
    if level > 2 and (start,cur) in line: 
        tmp = t1 * (t2+line[(start,cur)])
        if tmp < res:
            res = tmp
        return
        
    for nxt,c in road[cur]:
        if nxt not in visited:
            visited.add(nxt)
            dfs(start,nxt,level+1,t1+p[nxt],t2+c)
            visited.remove(nxt)
    

for start in range(n):
    src = 1 << start
    visited.add(src)
    dfs(src,src,1,p[src],0)
    visited.remove(src)

if res != float("inf"):
    print(res)
else:
    print(-1)


    

C++(g++ 7.5.0) 解法, 执行用时: 1260ms, 内存消耗: 98944K, 提交时间: 2023-05-19 20:46:38

#include<bits/stdc++.h>
using namespace std;
const int INF=1e9;
const int N=22;
int a[N],g[1<<N],dp[1<<N][N],s[1<<N];
int b[N][N];
int n;
int main(){
	scanf("%d",&n);
	for (int i=0;i<n;i++) scanf("%d",&a[i]);
	for (int i=0;i<(1<<n);i++) g[i]=INF;
	for (int i=0;i<n;i++) 
		for (int j=0;j<n;j++) scanf("%d",&b[i][j]);
	for (int k=0;k<n;k++){
		for (int i=0;i<(1<<n);i++) if ((i&(-i))==(1<<k)){
			if ((i==(1<<k))) {
			dp[i][k]=0;
			if (b[k][k]) g[i]=min(g[i],b[k][k]);
			continue;
			}
			int t=(i^(1<<k));
			t^=(t&(-t));
			for (int j=k+1;j<n;j++) if ((i>>j)&1){
				dp[i][j]=INF;
				for (int p=k+(t>0?1:0);p<n;p++) if (((i>>p)&1)&&b[p][j]&&p!=j&&dp[i^(1<<j)][p]!=INF){
					dp[i][j]=min(dp[i][j],dp[i^(1<<j)][p]+b[p][j]);
				}
				if (t&&dp[i][j]!=INF&&b[k][j]) {
				g[i]=min(g[i],dp[i][j]+b[k][j]);
				}
			}
		}
	}
	long long ans=1e18;
	for (int i=0;i<(1<<n);i++){
		if (i) s[i]=s[i^(i&(-i))]+a[(int)log2(i&(-i))];
		if (g[i]!=INF&&ans>1ll*s[i]*g[i]) {
		ans=min(ans,1ll*s[i]*g[i]);
		}
	}
	if (ans==1e18) puts("-1"); else printf("%lld\n",ans);
}

C++(clang++ 11.0.1) 解法, 执行用时: 4ms, 内存消耗: 472K, 提交时间: 2023-05-19 21:49:19

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll t,n,m,ans,sum,mi=1e9,k,x,y,r,dp[50][50],z=1e17,a[50],p[50][50];
void dfs(ll ans,ll sum,int x,int y)
{
	if(ans*sum>z)
	{
		return;
	}
	if(x==y)
	{
		z=min(z,ans*sum);
		return;
	}
	for(int i=1;i<=n;i++)
	{
		if(dp[x][i]&&!p[x][i])
		{
			p[x][i]=p[i][x]=1;
			dfs(ans+a[i],sum+dp[x][i],i,y);
			p[x][i]=p[i][x]=0;
		}
	}
}
void sovel()
{
	cin>>n;
    for(int i=1;i<=n;i++)
    {
    	cin>>a[i];
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			cin>>dp[i][j];
		}
	}
	for(int i=1;i<=n;i++)
	{
		p[i][i]=1;
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(i!=j&&dp[i][j])
			{
				p[j][i]=p[i][j]=1;
				dfs(a[j],dp[i][j],j,i);
				p[j][i]=p[i][j]=0;
			}
		}
	}
	if(z==1e17)
	{
		z=-1;
	}
	cout<<z;
}
int main() {
	t=1;
	while(t--)
	{
		sovel();
	 } 
	
}

上一题