整理04(二)

试题编号: 201609-4
试题名称: 交通规划
#include<bits/stdc++.h>
using namespace std;
struct Edge{
    int v,cost;
};
vector<Edge>graph[10005];//图
int N,M,result=0;
bool visit[10005];//当前顶点是否已访问过
int dis[10005],cost[10005];
void Dijkstra(){
    for(int ii=0;ii<N;++ii){//循环N次
        int v=-1,MIN=INT_MAX;
        for(int i=1;i<=N;++i)//得出当前有最短距离的未被访问的结点
            if(!visit[i]&&dis[i]<MIN){
                MIN=dis[i];
                v=i;
            }
        visit[v]=true;//当前结点已访问过
        result+=cost[v];//将到达当前结点的边长加和到最终结果中
        for(int i=0;i<graph[v].size();++i){//遍历当前结点能到达的结点
            int temp=graph[v][i].v;
            //取最短距离,如果最短距离相等,取到达结点最小的边
            if((!visit[temp]&&dis[temp]>dis[v]+graph[v][i].cost)||(dis[temp]==dis[v]+graph[v][i].cost&&cost[temp]>graph[v][i].cost)){
                dis[temp]=dis[v]+graph[v][i].cost;
                cost[temp]=graph[v][i].cost;
            }
        }
    }
}
int main(){
    scanf("%d%d",&N,&M);
    while(M--){//读取数据,注意所给图为无向图
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        graph[a].push_back({b,c});
        graph[b].push_back({a,c});
    }
    fill(dis+2,dis+N+1,INT_MAX);//指定填充
    Dijkstra();
    printf("%d",result);
    return 0;
}
试题编号: 201612-4
试题名称: 压缩编码

记住solve()函数

设dp[i][j]表示第i到第j堆石子合并的最优值,sum[i][j]表示第i到第j堆石子的总数量。那么就有状态转移公式:

1、dp[i][j]=0 (i==j)

2、dp[i][j]=min(dp[i][k]+dp[k][j])+sum[i][j] (i!=j)

此时算法复杂为O(n^3)。

这里可以利用平行四边形优化降为O(n^2):

由上面的方程式可知我们每次求dp[i][j]的关键是找到合适的k值,设p[i][j]为dp[i][j]的这个合适的k值,根据平行四边形规则有以下不等式:p[i][j-1]<=p[i][j]<=p[i+1][j]。

那么求解dp[i][i+L](L为长度)的复杂度就为:

(p[2,L+1]-p[1,L])+(p[3,L+2]-p[2,L+1])…+(p[n-L+1,n]-p[n-L,n-1])=p[n-L+1,n]-p[1,L]≤n。

复杂度为O(n)。然后L从1循环至n,总复杂度就为O(n^2)。

程序说明。:程序中,INT_MAX2值是个将就的做法,并不是整数最大值。

/* CCF201612-4 压缩编码 */
#include <iostream>
#include <cstring>
using namespace std;
const int INT_MAX2 = 0x7F7F7F7F;
const int N = 1000;
int v[N+1];
int sum[N+1];
int dp[N+1][N+1];
int solve(int l, int r)
{
    if(dp[l][r] == INT_MAX2)
        for(int i = l; i < r; i++)
            dp[l][r] = min(dp[l][r], solve(l, i) + solve(i+1, r) + sum[r] - sum[l-1]);
    return dp[l][r];
}
int main()
{
    int n;
    // 变量初始化:置为最大值
    memset(dp, INT_MAX2, sizeof(dp));
    // 输入数据
    cin >> n;
    sum[0] = 0;
    for(int i=1; i<=n; i++) {
        cin >> v[i];
        sum[i] = sum[i-1] + v[i];
        dp[i][i] = 0;
    }
    // DP计算
    solve(1, n);
    // 输出结果
    cout << dp[1][n] << endl;
    return 0;
}
试题编号: 201703-4
试题名称: 地铁修建

主要的算法思想是克鲁斯卡尔算法加上并查集

#include<bits/stdc++.h>
#include<cstdio>
using namespace std;
struct node{
	int u,v,w;
}table[200010];
bool cmp(node a,node b){
	return a.w <b.w ;
}
int father[100010];
int find(int x){
	return father[x]==x?x:father[x]=find(father[x]);
}
int main(){
	int n,m,ans;
	int a,b,c;
	scanf("%d%d",&n,&m);
		getchar();
		for(int i=1;i<=n;i++){
			father[i]=i;
		}
		for(int i=0;i<m;i++){
			cin>>table[i].u >>table[i].v >>table[i].w ;
		}
		sort(table,table+m,cmp);
		for(int i=0;i<m;i++){
			father[find(table[i].u )]=find(table[i].v );
			if(find(1)==find(n)){
				ans=table[i].w ;
				break;
			}
		}
		cout<<ans<<endl;
	
	return 0;
} 
试题编号: 201709-4
试题名称: 通信网络

样例输入

4 4
1 2
1 3
2 4
3 4

样例输出

2

样例说明

  部门1和部门4知道所有其他部门的存在。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值