算法设计与分析 实验八 网络流与复习

1.连续数组最大值:求最大连续子段和,并输出此子段的起始位置和终止位置的值。

例如给定序列{ -2, 11, -4, 13, -5, -2 },其最大连续子序列为{ 11, -4, 13 },最大和为20。

入:测试输入包含若干测试用例,每个测试用例占2行,第1行给出正整数K( < 10000 ),第2行给出K个整数,中间用空格分隔。当K为0时,输入结束,该用例不被处理。

出:对每个测试用例,在1行里输出最大和、最大连续子序列的第一个和最后一个元 素,中间用空格分隔。如果最大连续子序列不唯一,则输出序号i和j最小的那个(如输入样例的第2、3组)。若所有K个元素都是负数,则定义其最大和为0,输出整个序列的首尾元素。

入:6    -2 11 -4 13 -5 -2      出:20 11 13    当k=0时结束输入

#include<iostream>
#include<string>
using namespace std;
int x[100100],n;
int main() {
	while(cin>>n,n) {
		int i,j,kk=1;
		for(i=1; i<=n; ++i) {
			cin>>x[i];
			if(x[i]>=0){
				kk=0;
			}
		}
		int y=-(1<<29),f,g;
		if(kk) { 
			y=0; f=1; g=n;
		} else {
			int sum=0;
			f=g=1;
			for(int i=1,j=1; i<=n; i++) {
				sum+=x[i];
				if(sum>y) { 
					f=j; g=i; y=sum;
				}
				if(sum<0) {
					sum=0;
					j=i+1;
				}
			}
		}
		cout<<y<<" "<<x[f]<<" "<<x[g]<<endl;
	}
	return 0;
}

2.买最多:给出物品单价和重量,给出当前金额,问最多能买多重的物品,物品可拆。

入:输入数据第一行包含一个正整数t(t100),代表共有t组测试样例。每组测试样例的第一行包含两个正整数n和m(1n,m1500),分别代表有n块钱,有m种物品。接下来输入m行,每行包含两个正整数a,b(1a25,1b10)​​​​​​,分别代表当前物品的单价和重量。可认为当前金额买不了全部物品

出:对于每组输出占一行,保留2位小数。

入:1       6 3    4 2   3 2   2 2      出:2.67

#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include<iomanip>   
using namespace std;
int n,m,t;
double sum;
struct point {
	int v,w;
} po[1510];
bool hanshu(point x, point y);
int main() {
	cin>>t;
	for(int i=0;i<t;i++) {
		cin>>n>>m;
		for (int i = 0; i < m; i++) {
			cin>>po[i].v>>po[i].w;
		}
		sort(po,po+m,hanshu);  
        sum = 0.0;
		for (int i = 0; i < m; i++) {
			if (n >= po[i].v * po[i].w) {
				sum += po[i].w;
				n = n - po[i].v * po[i].w;
			} else {
				sum += n*1.0 / po[i].v;
				break;
			}
		}
		cout << fixed << setprecision(2) << sum << endl;
	}
	return 0;
}
bool hanshu(point x, point y) {
	if (x.v < y.v) {
		return true;
	} else if (x.v == y.v) {
		if (x.w < y.w) {
			return true;
		}
	}
	return false;
}

3.马的遍历:给出标准 8×8 国际象棋棋盘上的两个格子,马的移动方式为 “日” 字形(如下图所示),求马从起点 (x1, y1) 跳到终点 (x2, y2) 最少需要多少步。

入:输入一行,包含由空格分隔开的四个整数 x1, y1, x2, y2 (1 <= x1, y1, x2, y2 <= 8),分别表示起点和终点的横纵坐标。

出:输出一行,包含一个整数,表示从从起点 (x1, y1) 跳到终点 (x2, y2) 所需要的最少步数。

入:5 2 5 4

出:2

#include<iostream>
#include<queue>
#include<string>
#include<cstring>
using namespace std;
const int maxn = 30; onst int xpoint[10]= {0,2,-2,2,-2,-1,1,-1,1};
const int ypoint[10]= {0,1,1,-1,-1,2,2,-2,-2};
queue<pair<int,int> > que;
int shuzu[maxn][maxn];
int main() {
	int x1,y1,x2,y2;
	cin>>x1>>y1>>x2>>y2;
	memset(shuzu,-1,sizeof(shuzu));//变化数组 
	shuzu[x1][y1]=0;
	que.push(make_pair(x1,y1));
	while(que.size()) {
		int x = que.front().first,y = que.front().second;
		for(int i = 1; i <= 8; ++i) {
			int inx = x + xpoint[i];
			int iny = y + ypoint[i];
			if(inx >= 1 && inx <= 8 && iny >= 1 && iny <= 8 && shuzu[inx][iny] == -1) {
				shuzu[inx][iny] = shuzu[x][y] + 1;
				que.push(make_pair(inx,iny));
			}
			if(inx==x2&&iny==y2) {
				break;
			}
		}
		que.pop();
	}
	cout<<shuzu[x2][y2];
	return 0;
}

4.字符串拆分成菲薄纳西数列。输入一个只包含数字的字符串 s,比如 s = "01123",可以分成斐波那契序列 [0, 1, 1, 2, 3]。 斐波那契序列中,每个数字不能以0开头,除非数字为 0 。

入:输入数字字符串 s。1s.length200, 字符串 s 中只有数字。

出:输出斐波那契序列。如果有多组解,输出第一项最小的那组, 若第一项相等输出第二项最小的那组解。如果不能拆分则输出None。

入:1101111

出:11  0  11  11

#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#define INT_MAX 2147483647using namespace std;
typedef long long LL;
vector<int> get(string &s,LL a,LL b) {
	vector<int> res= {(int)a,(int)b};
	string t=to_string(a)+to_string(b);
	while(t.size()<s.size()) {
		auto c=a+b;
		if(c>INT_MAX) {
			return {};
		}
		res.push_back(c);
		t+=to_string(c);
		a=b,b=c;
	}
	if(t!=s) {
		return {};
	}
	return res;
}
vector<int> hanshu(string s) {
	for(int i=1; i<=10; i++) {
		for(int j=i+1; j <= i + 10 && j < s.size(); j++) {
			auto a = stoll(s.substr(0, i)), b = stoll(s.substr(i, j - i));
			auto res=get(s,a,b);
			if(res.size()) {
				return res;
			}
		}
	}
	return {};
}
string out(vector<int> vec, int len = -1) {
	if (len == -1) {
		len = vec.size();
	}
	if (len == 0) {
		return "[]";
	}
	string x;
	for(int index = 0; index < len; index++) {
		int number = vec[index];
		x += to_string(number) + " ";
	}
	return  x.substr(0, x.length() - 1) ;
}
int main() {
	string str;
	vector<int>a;
	while(cin>>str) {
		a=hanshu(str);
		if(a.empty()) {
			cout<<"None"<<endl;
		} else {
			string temp=out(a);
			cout<<temp<<endl;
		}
	}
	return 0;
}

5.回文字符串升级。给定一个非空字符串 s,最多删除一个字符。判断是否能成为回文字符串。

入:1s.length<2.6*106

出:输出true or false

入:abca

出:true

#include<iostream>
#include<string>
#include<cstring>
#include<vector>
using namespace std;
bool check(int i,int k,string a,bool m) {
	if (m==0) {
		++i;
	} else if (m==1) {
		--k;
	}
	while(i<=k) {
		if (a[i]==a[k]) {
			i++;
			k--;
		} else if (a[i]!=a[k]) {
			return false;
		}
	}
	return true;
}
bool hanshu(string a) {
	int i = 0;
	int k = a.size()-1;
	while(i<=k) {
		if (a[i]==a[k]) {
			++i;
			--k;
		} else if(a[i]!=a[k]) {
			return ((check(i,k,a,0)) || (check(i,k,a,1)));
		}
	}
	return true;
}

string change(bool a) {
	if(a){
		return "true";
	}else{
		return "false";
	}
}
int main() {
	string str;
	while(cin>>str){
		bool temp=hanshu(str);
		string x=change(temp);
		cout<<x<<endl;
	}
	return 0;
}

6.最大流问题:给出一张网络有向图,源点及汇点,计算其最大流。 该网络中的顶点编号为1~N,发点和汇点在输入中指定。

入:第一行给出四个整数N M(N <= M <= 5000),S,T,分别表示节点数量、有向边数量、源点序号、汇点序号。接下来M行每行包括三个正整数ui,vi,wi,表示第 i条有向边从 ui出发,到达 vi,边权为 wi。

出:一行,包括一个正整数,为该网络流最大流。

入:6 9 4 2     1 3 10    2 1 20    2 3 20     4 3 10    4 5 30   5 2 20    4 6 20    5 6 10    6 2 30

出:50

#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include<queue>
#define maxn 10010using namespace std;
int n,m,s,t,_a, ans;int shuzu1[maxn], shuzu2[maxn];
const int minn = 1e9;
struct point {
	int y, w, z, next;
} po[maxn];
void add(int x, int y, int a) {
	po[++_a] = (point) {
		y, a, _a + 1, shuzu2[x]
	};
	shuzu2[x] = _a;
	po[++_a] = (point) {
		x, 0, _a - 1, shuzu2[y]
	};
	shuzu2[y] = _a;
}
bool bfs() {
	queue<int>q;
	for (int i = 1; i <= n; ++i) {
		shuzu1[i] = minn;
	}
	shuzu1[s] = 0;
	q.push(s);
	while (q.size()) {
		int x = q.front();
		q.pop();
		for (int i = shuzu2[x]; i; i = po[i].next) {
			int y = po[i].y;
			if (shuzu1[y] > shuzu1[x] + 1 && po[i].w) {
				shuzu1[y] = shuzu1[x] + 1;
				q.push(y);
				if (y == t) {
					return 1;
				}
			}
		}
	}
	return 0;
}
int dfs(int x, int k) {
	int temp = 0; int i = shuzu2[x];
	if (x == t) {
		return k;
	}
	for (i; i; i = po[i].next) {
		int y = po[i].y;
		if (po[i].w && shuzu1[y] == shuzu1[x] + 1) {
			int b = dfs(y, min(po[i].w, k - temp));
			if (!b) {
				shuzu1[y] = -1;
			}
			po[i].w -= b;
			po[po[i].z].w += b;
			temp += b;
			if (temp == k) {
				break;
			}
		}
	}
	return temp;
}
int main() {
	cin>>n>>m>>s>>t;
	for (int i = 1; i <= m; ++i) {
		int var1,var2,var3;
		cin>>var1>>var2>>var3;
		add(var1, var2, var3);
	}
	while (bfs()) {
		ans += dfs(s, minn);
	}
	cout<<ans<<endl;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

stearm210

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值