void get_nextval(char p[], int ne[])
{
int m = strlen(p);
for (int i = 2 , j = 0 ; i < m ; i ++ )
{
while(j && p[i] != p[j+1]) j = ne[j];
if(p[i] == p[j+1]) j ++ ;
ne[i] = j;
}
}
int Index_KMP(char s[], char p[], int pos, int ne[])
{
int n = strlen(s);
int m = strlen(p);
int f = 0;
m --;
for (int i = 1 , j = 0 ; i < n ; i ++ )
{
while(j && s[i] != p[j+1]) j = ne[j];
if(s[i] == p[j+1]) j ++ ;
if(j == m)
{
f = i - m + 1;
break;
}
}
return f;
}
bool Delete( HashTable H, ElementType Key ){
int place=Hash(Key,H->TableSize);
PtrToLNode p=H->Heads[place].Next;
PtrToLNode pf=&H->Heads[place];
while(p){
if(!strcmp(Key,p->Data))
{
pf->Next=p->Next;
free(p);
printf("%s is deleted from list Heads[%d]\n",Key,place);
return true;
}
pf=p;
p=p->Next;
}
return false;
}
6-35 最长公共子序列 (10 分)
void LCS(int m ,int n, char *x, int **b)
{
if(m == 0 || n == 0 ) return;
if(b[m][n] == 1){
LCS(m - 1,n - 1,x,b);
cout << x[m] << ' ';
}
else if(b[m][n] == 2){
m = m - 1;
LCS(m,n,x,b);
}
else if(b[m][n] == 3){
n = n - 1;
LCS(m,n,x,b);
}
}
/*
4
5
a c d f
a d g h m
a d
https://wenku.baidu.com/view/b4a7687ffe00bed5b9f3f90f76c66137ee064fb0.html
*/
6-36 最长公共子序列 (15 分)
no code!
6-37 求解拆分集合为相等的子集合问题(动态规划法) (30 分)
int split(int n)
{
int sum = n * (n + 1) / 4;
dp[0][0] = 1;
for(int i = 1;i <= n;i ++){
for(int k = 0;k <= sum;k ++){
if(i > k)
dp[i][k] = dp[i - 1][k];
else
dp[i][k] = dp[i - 1][k] + dp[i - 1][k - i];
}
}
return dp[n][sum] / 2;
}
// https://www.cnblogs.com/kangjianwei101/p/5332451.html
#include <iostream>
using namespace std;
const int N = 10010;
int s, n;
int h[N];
bool is_prime(int x)
{
if (x == 1) return false;
for (int i = 2; i * i <= x; i ++ )
if (x % i == 0)
return false;
return true;
}
int find(int x)
{
int t = x % s;
for (int k = 0; k < s; k ++ )
{
int i = (t + k * k) % s;
if (!h[i]) return i;
}
return -1;
}
int main()
{
cin >> s >> n;
while (!is_prime(s)) s ++ ;
for (int i = 0; i < n; i ++ )
{
int x;
cin >> x;
int t = find(x);
if (t == -1) printf("-");
else
{
h[t] = x;
printf("%d", t);
}
if (i != n - 1) printf(" ");
}
return 0;
}
/*
注意k的精度!!!!!!!!!!!
注意k的精度!!!!!!!!!!!
注意k的精度!!!!!!!!!!!
注意k的精度!!!!!!!!!!!
注意k的精度!!!!!!!!!!!
*/
#include <iostream>
#include <cstring>
#include <unordered_map>
#include <algorithm>
using namespace std;
const int N = 1e4+10;
struct Moon{
double weight;
double sale;
double ave;
}moon[N];
int n;
double k;
int main()
{
cin >> n >> k;
for(int i = 0;i < n;i++)
{
cin >> moon[i].weight ;
}
for(int i = 0;i < n;i++)
{
cin >> moon[i].sale;
moon[i].ave = moon[i].sale * 1.0 / moon[i].weight;
}
sort(moon,moon+n,[](Moon m1,Moon m2){
return m1.ave > m2.ave;
});
double sum = 0;
for(int i = 0;i < n;i++)
{
if(moon[i].weight < k)
{
k -= moon[i].weight;
sum += moon[i].sale;
}
else
{
sum += k * 1.0 * moon[i].ave;
break;
}
}
printf("%.2lf\n",sum);
return 0;
}
7-46 加油站之最小加油次数 (15 分)
#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
int main()
{
int n;
int s,h;
cin >> n;
vector<PII>vec;
for(int i = 0;i < n;i ++){
int a,b;
cin >> a >> b;
vec.push_back({a,b});
}
cin >> s >> h;
sort(vec.begin(),vec.end(),[](PII p1,PII p2){
return p1.first > p2.first;
});
priority_queue<int>heap;
int cnt = 0;
for(int i = 0;i < n;i ++){
while(vec[i].first < s - h){
if(heap.size() == 0){
cout << -1 << endl;
return 0;
}
h += heap.top();
heap.pop();
cnt ++;
}
h = h - (s - vec[i].first);
s = vec[i].first;
heap.push(vec[i].second);
}
cout << cnt << endl;
return 0;
}
7-47 活动选择问题 (25 分)
#include<iostream>
#include<algorithm>
#define MAXN 1000
using namespace std;
struct Goods {
int s;
int e;
}goods[MAXN];
bool comp(Goods a, Goods b)
{
return a.e <= b.e;
}
void input(int n)
{
int i;
for (i = 0; i <n; i++)
cin >> goods[i].s >> goods[i].e; //输入活动开始和结束的时间
}
void select(int n)
{
int sum = -1;
int count = 0;
for (int i = 0; i < n; i++)
{
if (goods[i].s >= sum)
{
count++;
sum = goods[i].e;
}
}
cout << count << endl;//能安排的活动个数
}
int main()
{
int n;//活动的总数
while (cin >> n)
{
if (n == 0)break;
input(n);
sort(goods, goods+n, comp);//按活动结束时间从小到大排序
select(n);
}
return 0;
}
7-48 最小生成树-kruskal (10 分)
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e6 + 10;
int n, m, p[N];
void init(){
for (int i = 1; i <= n; i++){
p[i] = i;
}
}
struct Edge{
int x, y, w;
bool operator < (const Edge &W)const
{
return w < W.w;
}
}edges[N];
int Find(int x ){
if (p[x] != x) p[x] = Find(p[x]);
return p[x];
}
int kruskal(){
sort(edges,edges + m);
int res = 0;
int cnt = 0;
init();
for (int i = 0; i < m; i++){
int x = edges[i].x, y = edges[i].y, w = edges[i].w;
if (Find(x) != Find(y)){
p[Find(x)] = Find(y);
cnt ++;
res += w;
}
}
if (cnt < n - 1) return -1;
else return res;
}
int main(){
scanf("%d%d",&n,&m);
for (int i = 0; i < m; i++){
int a, b, c;
scanf("%d%d%d",&edges[i].x,&edges[i].y,&edges[i].w);
}
int t = kruskal();
if (t == -1) puts("impossible");
else printf("%d\n",t);
return 0;
}
7-49 最小生成树-prim (10 分)
#include <cstring>
#include <iostream>
#include <algorithm>
#define inf 0x3f3f3f3f
using namespace std;
const int N = 1e6+10, M = 2e6+10;
int n,m;
int p[N];
struct Edge
{
int a, b, w;
bool operator < (const Edge &W)const
{
return w < W.w;
}
}edges[M];
int find(int x)
{
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
int kruskal()
{
sort(edges, edges + m);
for (int i = 1; i <= n; i ++ ) p[i] = i; // 初始化并查集
int res = 0, cnt = 0;
for (int i = 0; i < m; i ++ )
{
int a = edges[i].a, b = edges[i].b, w = edges[i].w;
a = find(a), b = find(b);
if (a != b)
{
p[a] = b;
res += w;
cnt ++ ;
}
}
return res;
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 0; i < m; i ++ )
{
int a, b, w;
scanf("%d%d%d", &a, &b, &w);
edges[i] = {a, b, w};
}
int t = kruskal();
printf("%d\n", t);
return 0;
}
7-50 最优服务次序问题 (10 分)
#include<iostream>
#include<algorithm>
using namespace std;
int main(){
int n,a[1000];
cin>>n;
int i;
for(i=0;i<n;i++){
cin>>a[i];
}
sort(a,a+n);
int sum=0;
for(i=0;i<n;i++){
sum+=a[i]*(n-i - 1);
}
// cout<<sum/(n*1.0)<<endl;
printf("%.2lf\n",sum*1.0/n);
return 0;
}
#include <iostream>
#include <algorithm>
using namespace std;
int a[1000];
int s[1000];
int cmp(int a,int b)
{
return a>b;
}
int main()
{
int n,m;
int len;
int sum;
while(cin>>n>>m)
{
for(int i=0;i<=n-1;i++)
{
cin>>a[i];
}
sort(a,a+n);
len=a[n-1]-a[0]+1;
for(int i=0;i<n-1;i++)//求区间的间隔距离
{
s[i]=a[i+1]-a[i]-1;
}
sort(s,s+n-1,cmp);
sum=len;
for(int i=0;i<m-1;i++)
{
sum=sum-s[i];
}
cout << sum << endl;
}
return 0;
}
// https://blog.youkuaiyun.com/baidu_30309461/article/details/48399161
7-53 哈夫曼编码 (30 分)
// HuffmanCodes.cpp : 定义控制台应用程序的入口点。
//
//#include <stdafx.h>
#include <vector>
#include <iostream>
#include <string.h>
using namespace std;
//Huffman树结点类
class Node {
public:
Node() {}
Node(char element, int weight)
:element(element), weight(weight), left(NULL), right(NULL) {}
char element;
int weight;
Node* left = NULL;
Node* right = NULL;
bool isleave = false;
};
typedef Node* HFMTree;
//输入测试样例结点类
class Case {
public:
char element;
char route[1000];
int length;
int getlength() {
return strlen(this->route);
}
};
void Read(int num, vector<HFMTree>& minHeap, vector<HFMTree>& inputlist);
void Insert(vector<HFMTree>& minHeap, HFMTree node); //插入数据创建最小堆
HFMTree CreateHFMT(vector<HFMTree>& minHeap); //根据最小堆创建Huffman树
HFMTree DeleteMinHeap(vector<HFMTree>& minHeap); //从最小堆中取出最小元素,删除该结点并重新调整最小堆,最后删除该结点
int getHFMLength(HFMTree hfmtree, int depth); //获得该树编码长度
void Input(vector<Case>& testcase, int num);
bool isOptimalLen(vector<Case>& testcase, vector<HFMTree>& inputlist, int weight); //检查是否符合最优编码长度
bool isPrefixCode(vector<Case>& testcase); //检查是否符合前缀码编码
int main()
{
/*根据输入序列建立Huffman树,并获得最优编码长度*/
int num;
cin >> num;
vector<HFMTree> minHeap; //创建最小堆,用最小堆对序列进行存储
vector<HFMTree> inputlist; //记录输入顺序与权值大小
HFMTree flag = new Node('-', -1);
minHeap.push_back(flag);
Read(num, minHeap, inputlist);
HFMTree hfmtree; //利用最小堆创建Huffman树
hfmtree = CreateHFMT(minHeap);
int optcodelength = getHFMLength(hfmtree, 0); //通过序列创建的Huffman树获得最优编码长度
/*对提交数据进行检查:1.是否符合最优编码长度,2.是否符合无歧义解码规则(前缀码编码,数据仅存在于二叉树叶节点)*/
int count;
cin >> count;
for (int i = 0;i < count;i++) {
vector<Case> testcase;
Input(testcase, num);
bool isoptimallen = isOptimalLen(testcase, inputlist, optcodelength);
bool isprefixcode = isPrefixCode(testcase);
if (isoptimallen && isprefixcode) {
cout << "Yes" << endl;
}
else {
cout << "No" << endl;
}
}
system("pause");
return 0;
}
void Read(int num, vector<HFMTree>& minHeap, vector<HFMTree>& inputlist) {
char element;
int weight;
for (int i = 0; i < num; i++) {
cin >> element >> weight;
HFMTree node = new Node(element, weight);
inputlist.push_back(node);
Insert(minHeap, node);
}
//minHeap.erase(minHeap.begin());
}
void Insert(vector<HFMTree>& minHeap, HFMTree node) {
int index = minHeap.size();
minHeap.push_back(node);
//每次插入后自底向上进行调整
while ((*minHeap[index / 2]).weight > (*node).weight) {
//此处不可单纯进行值交换,需要交换两个对象
//(*minHeap[index]).element = (*minHeap[index / 2]).element;
//(*minHeap[index]).weight = (*minHeap[index / 2]).weight;
minHeap[index] = minHeap[index / 2];
index /= 2;
}
minHeap[index] = node;
}
HFMTree CreateHFMT(vector<HFMTree>& minHeap) {
HFMTree hfmtree = new Node();
int size = minHeap.size() - 1;
//进行size-1次合并
for (int i = 1; i < size; i++) {
HFMTree node = new Node();
//每次从最小堆中取出堆顶的两个结点作为该结点的左右子结点
node->left = DeleteMinHeap(minHeap);
node->right = DeleteMinHeap(minHeap);
node->weight = node->left->weight + node->right->weight;
//将该结点作为根节点的二叉树重新加入最小堆
Insert(minHeap, node);
}
//从最小堆中取出建好的Huffman树
hfmtree = DeleteMinHeap(minHeap);
return hfmtree;
}
HFMTree DeleteMinHeap(vector<HFMTree>& minHeap) {
//检查是否堆空
if (minHeap.size() == 1) {
return NULL;
}
//将该堆最大元素装入新结点并返回
HFMTree node = new Node();
node = minHeap[1];
//重新调整该堆
int size = minHeap.size();
int parent, child;
//用最大堆中最后一个元素从根结点开始向上过滤下层结点
HFMTree cmp = new Node();
cmp = minHeap[size - 1];
//从根节点开始,用parent记录根结点下标,用child记录其最小子结点下标,每次循环将parent更新为上一次循环的child
//当parent指向底层结点时跳出循环(会有极端情况比如偏向一边的堆使得parent最终并非指向该子树底层结点,但不影响结果)
for (parent = 1; 2 * parent < size; parent = child) {
child = parent * 2;
//若该子结点不是堆尾结点,令child指向左右子结点中的较小者
if ((child != size - 1) && ((*minHeap[child]).weight > (*minHeap[child + 1]).weight)) {
child++;
}
//当循环到堆尾结点值小于等于该子结点值时,可以结束(此时堆尾结点会替换parent结点而不是child结点)
if (cmp->weight <= (*minHeap[child]).weight) {
break;
}
else {
minHeap[parent] = minHeap[child];
}
}
//将尾结点与当前父结点替换
minHeap[parent] = cmp;
//删除堆尾结点
//此处不能用minHeap.erase(minHeap.end());,因为erase会返回被删除结点的下一结点,而尾结点的下一结点超限
minHeap.pop_back();
//返回该结点
return node;
}
int getHFMLength(HFMTree hfmtree, int depth) {
//若为叶子节点,直接返回其编码长度
if (!hfmtree->left && !hfmtree->right) {
return hfmtree->weight * depth;
}
//否则其他节点一定有两个子树,返回左右子树编码长度之合,深度相应加一
else {
return getHFMLength(hfmtree->left, depth + 1) + getHFMLength(hfmtree->right, depth + 1);
}
}
void Input(vector<Case>& testcase, int num) {
for (int i = 0;i < num;i++) {
Case inputcase;
cin >> inputcase.element >> inputcase.route;
inputcase.length = inputcase.getlength();
testcase.push_back(inputcase);
}
}
bool isOptimalLen(vector<Case>& testcase, vector<HFMTree>& inputlist, int weight) {
int testweight = 0;
for (int i = 0;i < testcase.size();i++) {
testweight += (testcase[i].length * (*inputlist[i]).weight);
}
if (testweight == weight) {
return true;
}
else {
return false;
}
}
bool isPrefixCode(vector<Case>& testcase) {
bool isprefixcode = true;
HFMTree newtree = new Node();
//两种情况验证不满足前缀码要求:1.后创建的分支经过或超过已经被定义的叶子结点,2.后创建分支创建结束时未达到叶子结点
for (int i = 0;i < testcase.size();i++) {
HFMTree point = newtree;
if (isprefixcode == false)break;
for (int j = 0;j < testcase[i].length;j++) {
if (isprefixcode == false)break;
if (testcase[i].route[j] == '0') {
//先检查左子结点是否存在,若不存在,则创建一个左子结点
if (!point->left) {
HFMTree newnode = new Node();
point->left = newnode;
point = point->left;
//若此时为分支的最后一环,则将该结点定义为叶子结点
if (j == testcase[i].length - 1) {
point->isleave = true;
}
}
//若左子树存在,则先将标记指针移至左子树。
else {
point = point->left;
//若左子树为叶子结点,则不符合要求
if (point->isleave) {
isprefixcode = false;
break;
}
//若此时为分支的最后一环且仍有叶子结点,则不符合要求
if ((j == testcase[i].length - 1) && (point->left || point->right)) {
isprefixcode = false;
break;
}
}
}
else if (testcase[i].route[j] == '1') {
//先检查右子结点是否存在,若不存在,则创建一个右子结点
if (!point->right) {
HFMTree newnode = new Node();
point->right = newnode;
point = point->right;
//若此时为分支的最后一环,则将该结点定义为叶子结点
if (j == testcase[i].length - 1) {
point->isleave = true;
}
}
//若左子树存在,则先将标记指针移至左子树。
else {
point = point->right;
//若左子树为叶子结点,则不符合要求
if (point->isleave) {
isprefixcode = false;
break;
}
//若此时为分支的最后一环且仍有叶子结点,则不符合要求
if ((j == testcase[i].length - 1) && (point->left || point->right)) {
isprefixcode = false;
break;
}
}
}
}
}
return isprefixcode;
}
7-54 最短路径-Dijkstra (15 分)
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6;
typedef pair<int,int> pii;
int n,m;
int h[N],ne[N],e[N],w[N],idx;
int dist[N];
bool st[N];
void add(int a,int b,int c)
{
e[idx] = b,ne[idx] = h[a],w[idx] = c,h[a] = idx ++ ;
}
void dijkstra(int s)
{
memset(dist,0x3f,sizeof dist);
dist[s] = 0;
priority_queue<pii,vector<pii>,greater<pii> > heap;
heap.push({0,s});
while(heap.size())
{
auto t = heap.top();
heap.pop();
int u = t.second;
if(st[u]) continue;
st[u] = true;
for (int i = h[u] ; i != -1 ; i = ne[i])
{
int p = e[i];
if(dist[p] > dist[u] + w[i])
{
dist[p] = dist[u] + w[i];
heap.push({dist[p],p});
}
}
}
}
int main()
{
memset(h,-1,sizeof h);
int op;
cin >> n >> m >> op;
for (int i = 0 ; i < m ; i ++ )
{
int x,y,z;
cin >> x >> y >> z;
add(x,y,z);
if(!op){
add(y,x,z);
}
}
int s;
cin >> s;
dijkstra(s);
for(int i = 1;i <= n;i ++){
if(dist[i] == 0x3f3f3f3f){
printf("%d->%d:no path\n",s,i);
}else{
printf("%d->%d:%d\n",s,i,dist[i]);
}
}
return 0;
}
7-55 最优二叉搜索树 (10 分)
#include <bits/stdc++.h>
using namespace std;
double b[15], a[15], m[15][15], w[15][15];
int s[15][15], n, MAX = 0x3f3f3f3f, tr[1025];
void obst() {
for (int i = 0; i <= n + 1; ++i) {
m[i][i - 1] = 0.0;
w[i][i - 1] = a[i - 1];
}
for (int l = 1; l <= n; ++l) {
for (int i = 1; i <= n - l + 1; ++i) {
int j = i + l - 1;
int i1 = s[i][j - 1] > i ? s[i][j - 1] : i;
int j1 = s[i + 1][j] > i ? s[i + 1][j] : j;
m[i][j] = (double)MAX;
w[i][j] = w[i][j - 1] + b[j] + a[j];
for (int r = i1; r <= j1; ++r) {
double t = m[i][r - 1] + m[r + 1][j] + w[i][j];
if (t <= m[i][j]) m[i][j] = t, s[i][j] = r;
}
}
}
}
void getTree(int i, int j, int root) {
tr[root] = s[i][j];
if (i >= j) return;
getTree(i, s[i][j] - 1, root << 1);
getTree(s[i][j] + 1, j, root << 1 | 1);
}
void preOrder(int root) {
if (tr[root] == 0) {
printf(". ");
return;
}
printf("%d ", tr[root]);
preOrder(root << 1);
preOrder(root << 1 | 1);
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) scanf("%lf", &b[i]);
for (int i = 0; i <= n; ++i) scanf("%lf", &a[i]);
obst();
printf("%.2f\n", m[1][n]);
getTree(1, n, 1);
preOrder(1);
return 0;
}
7-56 最长递增子序列 (30 分)
#include <bits/stdc++.h>
using namespace std;
const int N = 2510;
int a[N];
int dp[N];
int main()
{
int n;
cin >> n;
for(int i = 1;i <= n;i ++)
cin >> a[i];
int ans = 0;
for(int i = 1;i <= n;i ++){
dp[i] = 1;
for(int j = 1;j < i;j ++){
if(a[i] > a[j])
dp[i] = max(dp[j] + 1,dp[i]);
ans = max(ans,dp[i]);
}
}
cout << ans << endl;
return 0;
}
7-57 最小费用流 (100 分)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=100010;
bool vis[maxn];
int n,m,s,t,x,y,z,f,dis[maxn],pre[maxn],last[maxn],flow[maxn],maxflow,mincost;
//dis最小花费;pre每个点的前驱;last每个点的所连的前一条边;flow源点到此处的流量
struct Edge{
int to,next,flow,dis;//flow流量 dis花费
}edge[maxn];
int head[maxn],num_edge;
queue <int> q;
void add_edge(int from,int to,int flow,int dis)
{
edge[++num_edge].next=head[from];
edge[num_edge].to=to;
edge[num_edge].flow=flow;
edge[num_edge].dis=dis;
head[from]=num_edge;
}
bool spfa(int s,int t)
{
memset(dis,0x7f,sizeof(dis));
memset(flow,0x7f,sizeof(flow));
memset(vis,0,sizeof(vis));
q.push(s); vis[s]=1; dis[s]=0; pre[t]=-1;
while (!q.empty())
{
int now=q.front();
q.pop();
vis[now]=0;
for (int i=head[now]; i!=-1; i=edge[i].next)
{
if (edge[i].flow>0 && dis[edge[i].to]>dis[now]+edge[i].dis)//正边
{
dis[edge[i].to]=dis[now]+edge[i].dis;
pre[edge[i].to]=now;
last[edge[i].to]=i;
flow[edge[i].to]=min(flow[now],edge[i].flow);//
if (!vis[edge[i].to])
{
vis[edge[i].to]=1;
q.push(edge[i].to);
}
}
}
}
return pre[t]!=-1;
}
void MCMF()
{
while (spfa(s,t))
{
int now=t;
maxflow+=flow[t];
mincost+=flow[t]*dis[t];
while (now!=s)
{//从源点一直回溯到汇点
edge[last[now]].flow-=flow[t];//flow和dis容易搞混
edge[last[now]^1].flow+=flow[t];
now=pre[now];
}
}
}
int main()
{
memset(head,-1,sizeof(head)); num_edge=-1;//初始化
scanf("%d%d",&n,&m);
s = 1,t = n;
for (int i=1; i<=m; i++)
{
scanf("%d%d%d%d",&x,&y,&z,&f);
add_edge(x,y,z,f); add_edge(y,x,0,-f);
//反边的流量为0,花费是相反数
}
MCMF();
printf("%d %d",maxflow,mincost);
return 0;
}
// https://www.luogu.com.cn/problem/solution/P3381
7-58 最大流 加强版 (200 分)
#include<bits/stdc++.h>
#define RIT register int
#define up(l,r,i) for(RIT i=l;i<=r;++i)
#define lw(l,r,i) for(RIT i=l;i>=r;--i)
#define erg(u) for(RIT i=head[u];i;i=nxt[i])
using namespace std;
const int INF =2147483647;
const int MAXN = 1200+3,MAXM =120000+3;
int n,m,s,t,mxflow,cnt;
bool inque[MAXN];
int lft[MAXN],gap[MAXN],ht[MAXN];
int ver[MAXM*2],head[MAXM*2],nxt[MAXM*2],val[MAXM*2],tot=1;
inline int qread(){
RIT ret,c;
while((c=getchar())> '9'||c< '0');
ret=c-'0';
while((c=getchar())>='0'&&c<='9')
ret=ret*10+c-'0';
return ret;
}
inline void add(){
RIT u=qread(),v=qread(),k=qread();
ver[++tot]=v,nxt[tot]=head[u],head[u]=tot,val[tot]=k;
ver[++tot]=u,nxt[tot]=head[v],head[v]=tot,val[tot]=0;
}
inline void bfs(){
queue<int> q;
for(q.push(t),ht[t]=0,inque[t]=true;!q.empty();){
RIT u=q.front(),v;inque[u]=false,q.pop();
erg(u)if(ht[v=ver[i]]>ht[u]+1&&val[i^1]&&!inque[v])
ht[v]=ht[u]+1,q.push(v),inque[v]=true;
}
up(1,n,i) if(ht[i]!=INF) gap[ht[i]]++;
}
inline void update(int u){
ht[u]=INF;
erg(u)if(ht[u]>1+ht[ver[i]]&&val[i])ht[u]=ht[ver[i]]+1;
}
struct cmp{
inline bool operator () (int a,int b) const{
return ht[a]<ht[b];}
};
inline int HIPP(){
up(1,n,i) ht[i]=INF;bfs();
if(ht[s]==INF) return 0;
priority_queue<int,vector<int>,cmp> pq;
erg(s){
lft[ver[i]]+=val[i],swap(val[i^1],val[i]);
if(ver[i]!=t&&ver[i]!=s&&!inque[ver[i]])
pq.push(ver[i]),inque[ver[i]]=true;
}
for(ht[s]=n;!pq.empty();){
RIT u=pq.top(),v;
inque[u]=false,pq.pop();
for(RIT i=head[u];i&&lft[u];i=nxt[i]){
if(!val[i]||ht[v=ver[i]]>=ht[u]) continue;
RIT mn=min(lft[u],val[i]);
lft[u]-=mn,val[i]-=mn,val[i^1]+=mn,lft[v]+=mn;
if(!inque[v]&&v!=s&&v!=t) pq.push(v),inque[v]=true;
}
if(!lft[u]) continue;
if(!(--gap[ht[u]])) up(1,n,i)
if(i!=s&&i!=t&&ht[i]>ht[u]&&ht[i]<n+1) ht[i]=n+1,cnt++;
update(u),++gap[ht[u]],pq.push(u),inque[u]=true;
if(cnt==n) return lft[t];
}
return lft[t];
}
int main(){
n=qread(),m=qread(),s=qread(),t=qread();
up(1,m,i) add();
printf("%d",HIPP());
return 0;
}
// https://www.luogu.com.cn/problem/solution/P4722
7-59 搭配飞行员 (100 分)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 110, M = 5210, INF = 1e8;
int m, n, S, T;
int h[N], e[M], f[M], ne[M], idx;
int q[N], d[N], cur[N];
void add(int a, int b, int c)
{
e[idx] = b, f[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
e[idx] = a, f[idx] = 0, ne[idx] = h[b], h[b] = idx ++ ;
}
bool bfs()
{
int hh = 0, tt = 0;
memset(d, -1, sizeof d);
q[0] = S, d[S] = 0, cur[S] = h[S];
while (hh <= tt)
{
int t = q[hh ++ ];
for (int i = h[t]; ~i; i = ne[i])
{
int ver = e[i];
if (d[ver] == -1 && f[i])
{
d[ver] = d[t] + 1;
cur[ver] = h[ver];
if (ver == T) return true;
q[ ++ tt] = ver;
}
}
}
return false;
}
int find(int u, int limit)
{
if (u == T) return limit;
int flow = 0;
for (int i = h[u]; ~i && flow < limit; i = ne[i])
{
cur[u] = i;
int ver = e[i];
if (d[ver] == d[u] + 1 && f[i])
{
int t = find(ver, min(f[i], limit - flow));
if (!t) d[ver] = -1;
f[i] -= t, f[i ^ 1] += t, flow += t;
}
}
return flow;
}
int dinic()
{
int r = 0, flow;
while (bfs()) while (flow = find(S, INF)) r += flow;
return r;
}
int main()
{
scanf("%d%d", &n, &m);
S = 0, T = n + 1;
memset(h, -1, sizeof h);
for (int i = 1; i <= m; i ++ ) add(S, i, 1);
for (int i = m + 1; i <= n; i ++ ) add(i, T, 1);
int a, b;
while (cin >> a >> b) add(a, b, 1);
printf("%d\n", dinic());
/*for (int i = 0; i < idx; i += 2)
if (e[i] > m && e[i] <= n && !f[i])
printf("%d %d\n", e[i ^ 1], e[i]);*/
return 0;
}
// https://www.luogu.com.cn/problem/P2756
7-60 数字梯形 (110 分)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1200, M = 4000, INF = 1e8;
int m, n, S, T;
int h[N], e[M], f[M], w[M], ne[M], idx;
int q[N], d[N], pre[N], incf[N];
bool st[N];
int id[40][40], cost[40][40];
void add(int a, int b, int c, int d)
{
e[idx] = b, f[idx] = c, w[idx] = d, ne[idx] = h[a], h[a] = idx ++ ;
e[idx] = a, f[idx] = 0, w[idx] = -d, ne[idx] = h[b], h[b] = idx ++ ;
}
bool spfa()
{
int hh = 0, tt = 1;
memset(d, -0x3f, sizeof d);
memset(incf, 0, sizeof incf);
q[0] = S, d[S] = 0, incf[S] = INF;
while (hh != tt)
{
int t = q[hh ++ ];
if (hh == N) hh = 0;
st[t] = false;
for (int i = h[t]; ~i; i = ne[i])
{
int ver = e[i];
if (f[i] && d[ver] < d[t] + w[i])
{
d[ver] = d[t] + w[i];
pre[ver] = i;
incf[ver] = min(f[i], incf[t]);
if (!st[ver])
{
q[tt ++ ] = ver;
if (tt == N) tt = 0;
st[ver] = true;
}
}
}
}
return incf[T] > 0;
}
int EK()
{
int cost = 0;
while (spfa())
{
int t = incf[T];
cost += t * d[T];
for (int i = T; i != S; i = e[pre[i] ^ 1])
{
f[pre[i]] -= t;
f[pre[i] ^ 1] += t;
}
}
return cost;
}
int main()
{
int cnt = 0;
scanf("%d%d", &m, &n);
S = ++ cnt;
T = ++ cnt;
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m + i - 1; j ++ )
{
scanf("%d", &cost[i][j]);
id[i][j] = ++ cnt;
}
// 规则1
memset(h, -1, sizeof h), idx = 0;
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m + i - 1; j ++ )
{
add(id[i][j] * 2, id[i][j] * 2 + 1, 1, cost[i][j]);
if (i == 1) add(S, id[i][j] * 2, 1, 0);
if (i == n) add(id[i][j] * 2 + 1, T, 1, 0);
if (i < n)
{
add(id[i][j] * 2 + 1, id[i + 1][j] * 2, 1, 0);
add(id[i][j] * 2 + 1, id[i + 1][j + 1] * 2, 1, 0);
}
}
printf("%d\n", EK());
// 规则2
memset(h, -1, sizeof h), idx = 0;
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m + i - 1; j ++ )
{
add(id[i][j] * 2, id[i][j] * 2 + 1, INF, cost[i][j]);
if (i == 1) add(S, id[i][j] * 2, 1, 0);
if (i == n) add(id[i][j] * 2 + 1, T, INF, 0);
if (i < n)
{
add(id[i][j] * 2 + 1, id[i + 1][j] * 2, 1, 0);
add(id[i][j] * 2 + 1, id[i + 1][j + 1] * 2, 1, 0);
}
}
printf("%d\n", EK());
// 规则3
memset(h, -1, sizeof h), idx = 0;
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m + i - 1; j ++ )
{
add(id[i][j] * 2, id[i][j] * 2 + 1, INF, cost[i][j]);
if (i == 1) add(S, id[i][j] * 2, 1, 0);
if (i == n) add(id[i][j] * 2 + 1, T, INF, 0);
if (i < n)
{
add(id[i][j] * 2 + 1, id[i + 1][j] * 2, INF, 0);
add(id[i][j] * 2 + 1, id[i + 1][j + 1] * 2, INF, 0);
}
}
printf("%d\n", EK());
return 0;
}
7-61 孤岛营救问题 (60 分)
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
const int N = 105,M = 12;
typedef pair<int,int> PII;
int g[N][N],key[N],d[N][1<<M];
bool st[N][1<<M];
int n,m,p,k,s;
int dx[] = {0,1,0,-1};
int dy[] = {1,0,-1,0};
queue<PII> q;
int get(int x,int y){
return (x - 1) * m + y;
}
int bfs(){
int t = get(1,1);
q.push({t,key[t]});
st[t][key[t]] = true;
memset(d,0x3f,sizeof d);
d[t][key[t]] = 0;
while(q.size()){
PII u = q.front();
q.pop();
int z = u.first,v = u.second;
for(int i = 0;i < 4;i++){
int x = (z - 1) / m + dx[i] + 1,y = (z - 1) % m + dy[i] + 1;
int v1 = v,z1 = get(x,y);
if(!x || !y || x > n || y > m || !g[z][z1]) continue;
if(g[z][z1] != -1){
if(!(v >> g[z][z1] & 1)) continue;
}
v1 |= key[z1];
if(!st[z1][v1]){
q.push({z1,v1});
st[z1][v1] = true;
d[z1][v1] = d[z][v] + 1;
}
if(z1 == n * m) return d[z1][v1];
}
}
return -1;
}
int main(){
cin>>n>>m>>p;
cin>>k;
int x1,y1,x2,y2,z,z1,z2;
memset(g,-1,sizeof g);
while(k--){
cin>>x1>>y1>>x2>>y2>>z;
z1 = get(x1,y1),z2 = get(x2,y2);
g[z1][z2] = g[z2][z1] = z;
}
cin>>s;
while(s--){
cin>>x1>>y1>>z;
key[get(x1,y1)] |= 1 << z;
}
cout<<bfs()<<endl;
return 0;
}