试题编号: | 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知道所有其他部门的存在。