71 城市建设
72 最大子阵
73 蚂蚁感冒 易 1
74 地宫取宝 易 1
75 斐波那契 易 1
76 小朋友排队 易 1
77 分糖果 易 1
78 兰顿蚂蚁 易 1
79 正则问题 易 1
80 分巧克力 易 1
81 日期问题 中 1
82 九宫幻方 易 1
83 拉马车 易 1
84 发现环 易 1
85 对局匹配 易 1
86 区间移位 易 1
87 矩阵翻硬币 易 1
88 邮局 易 1
89 包子凑数 易 1
90 波动数列 易 1
91 买不到的数目 易 1
92 促销购物 易 1
93 种树 易 1
94 能量项链 易 1
95 贪吃的大嘴 易 1
96 摆花 易 1
97 最长公共子序列 易 1
98 合并石子 易 1
99 矩阵乘法 易 1
100 fx权重 易 1
输入说明 :
输入的第一行包含两个整数n, m,分别表示C市中重要地点的个数和可以建设的道路条数。所有地点从1到n依次编号。
接下来m行,每行三个整数a, b, c,表示可以建设一条从地点a到地点b的道路,花费为c。若c为正,表示建设是花钱的,如果c为负,则表示建设了道路后还可以赚钱(比如建设收费道路)。
接下来一行,包含n个整数w_1, w_2, …, w_n。如果w_i为正数,则表示在地点i建设码头的花费,如果w_i为-1,则表示地点i无法建设码头。
输入保证至少存在一个方法使得任意两个地点能只通过新修的路或者河道互达。
对于20%的数据,1<=n<=10,1<=m<=20,0<=c<=20,w_i<=20;
对于50%的数据,1<=n<=100,1<=m<=1000,-50<=c<=50,w_i<=50;
对于70%的数据,1<=n<=1000;
对于100%的数据,1 <= n <= 10000,1 <= m <= 100000,-1000<=c<=1000,-1<=w_i<=1000,w_i≠0。
输出说明 :
输出一行,包含一个整数,表示使得所有地点通过新修道路或者码头连接的最小花费。如果满足条件的情况下还能赚钱,那么你应该输出一个负数。
比如:
输入
5 5
1 2 4
1 3 -1
2 3 3
2 4 5
4 5 10
-1 10 10 1 1
输出
9
说明:
建设第2、3、4条道路,在地点4、5建设码头,总的花费为9。
Kruscal:
#include<iostream>
#include<string>
#include<sstream>
#include <cmath>
#include<algorithm>
using namespace std;
struct edge{
int u,v,val;
}e[1000000];;
int set_pos[10010]={
0}; //被占用设为1
int N,M;
int N_pier=0;
struct pier{
int u,val;
}p[100000];
int pier_num_0_connect=0;
int pier_num_0_array[10010]={
0};
int change_land_road(int t){
e[t].val=0; return 0;
}
bool cmp(edge a,edge b){
return a.val<b.val;
}
bool cmp_2(pier a,pier b){
return a.val<b.val;
}
int find_min_path(){
int min_money=100000;
int x_tmp,y_tmp,t_tmp;
int kind;// 1 表示陆地 2表示水路
for(int i=1;i<=M;i++){
if(set_pos[e[i].u]+set_pos[e[i].v]==1) //判断是否一个在树内,一个在树外
if(e[i].val < min_money){
min_money=e[i].val;
kind = 1;
x_tmp = e[i].u;
y_tmp = e[i].v;
t_tmp = i;
break;
}
}
for(int i=1;i<=N_pier;i++)
if(set_pos[0]+set_pos[p[i].u]==1)
if(p[i].val < min_money){
min_money=p[i].val;
kind = 2;
x_tmp = 0;
y_tmp = p[i].u;
t_tmp = i;
break;
}
if(kind == 1){
//陆路
set_pos[x_tmp]=1;set_pos[y_tmp]=1;
change_land_road(t_tmp); //把选中的路权值设为0,这样最后还有权值为负的就分得清楚了
return min_money;
}
if(kind == 2){
//水路
set_pos[x_tmp]=1;set_pos[y_tmp]=1;
if(x_tmp == 0){
//设置的额外的信号量,记录多少点与0点相连,如果最后只有一个,那么就要删去
pier_num_0_array[pier_num_0_connect]=t_tmp;
pier_num_0_connect++;
}
return min_money;
}
}
int main(){
cin >> N >> M;
int total_money=0;
int x=0;
for(int i=1;i<=M;i++)
cin >> e[i].u >> e[i].v >>e[i].val;
for(int i=1;i<=N;i++){
cin >> x;
if(x>0){
N_pier++;
p[N_pier].u=i;
p[N_pier].val=x;
}
}
sort(e+1,e+M+1,cmp);
sort(p+1,p+N_pier+1,cmp_2);
set_pos[1]=1;
for(int i=0;i<N;i++){
total_money+=find_min_path();
}
//对于水路,滞后性处理
if(pier_num_0_connect==1){
int the_only_one_pier=pier_num_0_array[0];
total_money-=p[the_only_one_pier].val;
}
//对于陆路的,滞后性处理
for(int i=1;i<=M;i++){
if(e[i].val < 0)
total_money += e[i].val;
}
cout << total_money <<endl;
return 0;
}
Prim:
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
#define MAXN 10005
#define MAXM 100005
struct node{
int u,v,w;
}edge[MAXM+MAXN];
int fa[MAXN];
bool cmp(node a,node b)
{
return a.w<b.w;
}
int find(int x)
{
if(x==fa[x]) return x;
return fa[x]=find(fa[x]);
}
void init(int n)
{
for (int i=0;i<=n;i++)
fa[i]=i;
}
int kruscal(int n)
{
int fu,fv,w,sum=0;
for (int i=0;i<n;i++)
{
fu=find(edge[i].u);
fv=find(edge[i].v);
w=edge[i].w;
if (fu!=fv||w<0){
sum+=w;
fa[fu]=fv;
}
}
return sum;
}
int route(int n,int m)
{
init(n);
sort(edge,edge+m,cmp);
int ans=kruscal(m);
return ans;
}
int main()
{
int n,m,cost,i,fu,fv,f,k,ans,ans1;
while (cin>>n>>m)
{
for (i=0;i<m;i++)
cin>>edge[i].u>>edge[i].v>>edge[i].w;
k=m;
for (i=1;i<=n;i++)
{
cin>>cost;
if (cost!=-1)
{
edge[k].u=0;
edge[k].v=i;
edge[k++].w=cost;
}
}
init(n);
for (i=0;i<m;i++)
{
fu=find(edge[i].u);
fv=find(edge[i].v);
if (fu!=fv)
fa[fu]=fv;
}
f=find(1);
for (i=2;i<=n;i++)
{
if (f!=find(i))
break;
}
if (i==n+1)
{
ans=route(n,m); //考虑码头(即考虑0点)
ans1=route(n,k); //不考虑码头
if (ans>ans1)
cout<<ans1<<endl;
else cout<<ans;
continue;
}
cout<<route(n,k)<<endl;
}
return 0;
}
72 最大子阵
问题描述 :
给定一个n*m的矩阵A,求A中的一个非空子矩阵,使这个子矩阵中的元素和最大。
其中,A的子矩阵指在A中行和列均连续的一块。
输入说明 :
输入的第一行包含两个整数n, m,分别表示矩阵A的行数和列数。
接下来n行,每行m个整数,表示矩阵A。
对于50%的数据,1<=n, m<=50;
对于100%的数据,1<=n, m<=500,A中每个元素的绝对值不超过5000。
输出说明 :
输出一行,包含一个整数,表示A中最大的子矩阵中的元素和。
比如:
输入
3 3
-1 -4 3
3 4 -1
-5 -2 8
输出
10
说明:
取最后一列,和为10。
#include <stdio.h>
int main()
{
int n,m;
scanf("%d%d",&n,&m);
int dp[501][501]={
0};//初始化数组
int i,j;
int t;
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
scanf("%d",&t);
dp[i][j]=dp[i-1][j]+t;//dp存储的是当前所在位置前面的和(例如dp[2][1]=dp[0][0]+dp[1][0]+dp[2][0])
}
}
/*算法逻辑*/
int temp=0;
int max=-99999;
for(i=1;i<=n;i++)//循环一
{
for (j=1;j<=i;j++)//循环二 循环一和循环二实现的是矩阵行的组合
{
temp=0;
for(int k=1;k<=m;k++)
{
temp=dp[i][k]-dp[j-1][k]+temp;//(dp[i][k]-dp[j-1][k])是第k列第i行到第j行的和
if(temp>max)
max=temp;
if(temp<0)
temp=0;
}
}
}
printf("%d",max);
return 0;
}
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
int a[1000];
int main(){
int n;
scanf("%d",&n);
int i=0,j=0;
int ans=1;
for(i=0;i<n;i++)
{
scanf("%d",&a[i]);
}
int x=a[0];
if(x>0)//2
{
for(j=1;j<n;j++)
{
if(a[j]<0&&-a[j]>x)
{
ans++; //2.1
}
}
if(ans!=1)
{
for(j=1;j<n;j++)
{
if(a[j]>0&&a[j]<x)
{
ans++; //2.2
}
}
}
}
if(x<0)//2
{
for(j=1;j<n;j++)
{
if(a[j]>0&&a[j]<-x)
{
ans++; //2.3
}
}
if(ans!=1)
{
for(j=1;j<n;j++)
{
if(a[j]<0&&-a[j]>-x)
{
ans++; //2.4
}
}
}
}
printf("%d\n",ans);
return 0;
}
/*
T74 地宫寻宝
涉及到动态规划,深度优先搜索,四维数组,取余相关数学原理
*/
#include<stdio.h>
#include<string.h>
#define MAX_SIZE 51
int n, m, k;
int map[MAX_SIZE][MAX_SIZE];// 宝物地图
int dp[MAX_SIZE][MAX_SIZE][15][15];
int dfs(int x, int y, int sum, int max);
int main() {
int i = 0, j = 0;
scanf("%d%d%d", &n, &m, &k);
for (i = 1; i <= n; i++) {
for (j = 1; j <= m; j++) {
scanf("%d", &map[i][j]);
}
}
memset(dp, -1, sizeof(dp));// 初始化
printf("%d\n", dfs(1, 1, 0, -1));
return 0;
}
// 求方案的总数
// x y sum max分别表示坐标(x, y),当前宝物数量,当前宝物最大价值
int dfs(int x, int y, int sum, int max) {
int plans = 0;// 从当前坐标到出口的方案总数
if (dp[x][y][sum][max + 1] != -1) {
// 当前坐标已经计算过,则直接返回结果
return dp[x][y][sum][max + 1];
}
if (x == n && y == m) {
// 地宫出口,也即递归出口
if (map[x][y] > max) {
// 宝物价值大,可拿
if (sum == k || sum == k - 1) {
// 宝物拿够了或者只差一件,则方案可行
plans++;
}
}
else if (sum == k) {
plans++;
}
return dp[x][y][sum][max + 1] = plans;// 这里sum不变,因为求的是(x,y)点的方案
}
// 当前点不是出口,则有两种情况,向右走或者向下走(如果能走的话)
// 而从当前点到出口的方案总数就是向右走和向下走两个方向的方案总数之和
if (x + 1 <= n) {
// 向右走
// 决定了向右走,那么要看能不能拿当前点的宝物
if (map[x][y] > max) {
if (sum < k) {
// 宝物不够,拿
plans += dfs(x + 1, y, sum + 1, map[x][y]);
plans %= 1000000007;
}
}
plans += dfs(x + 1, y, sum, max);
plans %= 1000000007;
}
if (y + 1 <= m) {
// 向下走
if (map[x][y] > max) {
if (sum < k) {
plans += dfs(x, y + 1, sum + 1, map[x][y]);
plans %= 1000000007;
}
}
plans += dfs(x, y + 1, sum, max);
plans %= 1000000007;
}
dp[x][y][sum][max + 1] = plans;
return dp[x][y][sum][max + 1];
}
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
LL p;
LL qmul(LL a, LL b)
{
LL res = 0;
while (b)
{
if (b & 1) res = (res + a) % p;
a = (a + a) % p;
b >>= 1;
}
return res;
}
void mul(LL c[][2],LL a[][2],LL b[][2]) // c = a * b
{
static LL t[2][2];
memset(t,0,sizeof t);
for(int i = 0;i < 2;i++)
for(int j = 0;j < 2;j++)
for(int k = 0;k < 2;k++)
t[i][j