算法设计与分析 作业6

6-31 KMP算法 (15 分)


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;
}


6-32 哈希表的创建及查找(线性探查法) (10 分)

//输入不大于m的n个不为0(0表示空值)的数,
//用线性探查法解决冲突构造散列表
void CreateHash(HashTable HT[], int n) {//创作不易,点个赞吧,新春快乐~
	int hash_table[m];//创建一个辅助数组 
	int temp;//存放余数 
	for(int i=0; i<n; i++)
		cin >> hash_table[i]; 
	for(int i=0; i<m; i++)
		HT[i].key = 0;//初始化HT数组 
	for(int i=0; i<n; i++) {
		temp = hash_table[i] % 13;//求余数 
		if(HT[temp].key==0) {//如果正好有空就放进去 
			HT[temp].key = hash_table[i];
		} else { 
			int flag=0;
			for(int j=temp+1; j<n; j++) {//从余数位置往后看有没有空余位置 
				if(HT[j].key==0) {//如果有位置就放进去 
					HT[j].key = hash_table[i];
					flag = 1;
					break;
				}
			}
			if(flag==0) {//如果还是没有位置 
				for(int j=0; j<temp; j++) {//就从0位置往后找,找到余数位置之前 
					if(HT[j].key==0) {
						HT[j].key = hash_table[i];
						break;
					}
				}
			}
		}
	}
}
//输入一个值key,在散列表中查找key位置
int SearchHash(HashTable HT[],int key) {
	int temp = key % 13;//求余数
	for(int i=temp; i<m; i++) {//从余数位置往后查 
		if(HT[i].key == key)
			return i;
	}
	for(int i=0; i<temp; i++) {//从头查到余数位置之前 
		if(HT[i].key == key)
			return i;
	}
	return -1;
}


6-33 线性探测法的查找函数 (20 分)

Position Find( HashTable H, ElementType Key ){
	int place=Hash(Key,H->TableSize);
		int di=0;int firstspace=1;int space;int f=1;
		while((place+di)%H->TableSize!=place||f){
			f=0;
			if(H->Cells[(place+di)%H->TableSize].Info==Legitimate)
			{
				if(H->Cells[(place+di)%H->TableSize].Data==Key)
				return ((place+di)%H->TableSize);
			}
			else
			{
				if(firstspace)
				{
					space=(place+di)%H->TableSize;
					firstspace=0;
				}
			}
			di++;
		}
	if(firstspace)return ERROR;
	/*没有空位*/
	else return space; 
}


6-34 分离链接法的删除操作函数 (20 分)

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

6-38 求解最长递增子序列问题(动态规划法) (10 分)

void IncreaseOrder(int a[],int dp[],int x[][N],int n)
{
    for(int i = 0;i < n;i ++){
        dp[i] = 1;
        for(int j = 0;j < i;j ++){
            if(a[i] > a[j]){
                if(dp[i] < dp[j] + 1){
                    dp[i] = dp[j] + 1;
                    x[i][dp[j] - 1] = a[j];
                    x[i][dp[j]] = a[i];
                }
            }
        }
    }
}

6-39 最小生成树(普里姆算法) (10 分)

void Prim( AMGraph G, char v )
    { 
        int distance[G.vexnum];
        int parent[G.vexnum];
        //记录v的下标
        int index=0;
        int i,min=MaxInt,imin,count=0;
        // 1.初始化这棵树,即以v为起始点,同时初始化数组distance[]
        //     注:distance数组表示该树的任意一点到该点的最小距离

        //寻找v的下标
        for (i = 0; i < G.vexnum; i++)
        {
            if (G.vexs[i]==v)
            {
                index=i;
            }
            
        }
        for (i = 0; i < G.vexnum; i++)
        {
            if (i==index)
            {
                distance[i]=0;
                parent[i]=index;
            }else
            {
                distance[i]=G.arcs[index][i];
                parent[i]=index;
            }       
        }
        while (1)
        {
            if (count==G.vexnum-1)
            {
                break;
            }
            
            // 2.从小树现有的结点出发,寻找边权值最小的点:
            for ( i = 0; i < G.vexnum; i++){
                if (min>distance[i]&&distance[i]!=0)
                {
                    //记录最小值及其下标
                    min=distance[i];
                    imin=i;
                    
                }
                
            }
            //更新已到达过得节点数
			
            count++;
            // 3.找到后输出该边
            if (count<G.vexnum-1)
            {
                printf("%c->%c\n",G.vexs[parent[imin]],G.vexs[imin]);
            }else
            {
                printf("%c->%c",G.vexs[parent[imin]],G.vexs[imin]);
            }
            
            
            
            
            //初始化min以便下次寻找
            min=MaxInt;
            // 4.将该点的distance数组中的值赋值为0,标记已经遍历过
            distance[imin]=0;
            // 5.循环遍历结点,更新distance[]数组
            for ( i = 0; i < G.vexnum; i++){
                if (distance[i]!=0&&G.arcs[i][imin]<MaxInt)
                {
                    if (distance[i]>G.arcs[i][imin])
                    {
                        distance[i]=G.arcs[i][imin];
                        parent[i]=imin;
                    }                   
                }
            }            
        }
}
// https://blog.csdn.net/qq_46101869/article/details/105977813?


6-40 部分背包问题(贪心法) (10 分)

void Knap()
{
    for(int i = 1;i <= n;i ++){
        if(W >= A[i].w){
            W -= A[i].w;
            A[i].x = 1;
            V += A[i].v;
        }else{
            A[i].x = W/A[i].w;
            V += A[i].v * A[i].x;
            break;
        }
    }
}

6-41 哈夫曼树及编码 (10 分)

no code!

6-42 最短路径(迪杰斯特拉算法) (10 分)

void ShortestPath_DIJ(AMGraph G, int v0)
{
	for(int i = 0;i < G.vexnum;i ++){	
		D[i] = MaxInt;
		S[i] = 0;
	}
	
	D[v0] = 0;
    Path[v0] = -1;
	
	for(int i = 0;i < G.vexnum;i ++){
		int t = -1;
		for(int j = 0;j < G.vexnum;j ++){
			if(!S[j] && (t == -1|| D[j] < D[t])){
				t = j;
			}
		}
        if(t == -1) return;
		S[t] = 1;
	//	cout << t << ' ' << D[t] << endl;
        
		for(int j = 0;j < G.vexnum;j ++){
			if(D[j] > D[t] + G.arcs[t][j]){
				D[j] = D[t] + G.arcs[t][j];
				Path[j] = t;
			}
		}
	}
    
 //   for(int i = 0;i < G.vexnum;i ++){
        cout << D[i] << ' ';
  ///  }
	
} 

7-37 Hashing (25 分)

#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;
}

7-38 Hashing - Hard Version (30 分)

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <stack>
#include <queue>
#include <cmath>
using namespace std;
const int maxn=1010;
const int inf=999999;
vector<int> indegree;
bool visit[maxn];
int e[maxn][maxn];
int a[maxn];
int count[maxn];
int n,cnt;
void topSort(){     //拓扑排序
    queue<int> q;
    for(int i=0;i<n;i++){
        int u=-1,min=inf;
        for(int j=0;j<n;j++){
            if(visit[j]==false&&!indegree[j])
                if(a[j]<min){       //每次都选取最小的入队(其实用数组输出也一样)
                    min=a[j];
                    u=j;
                }
        }
        if(u==-1) break;
        visit[u]=true;
        q.push(a[u]);
        for(int v=0;v<n;v++){
            if(visit[v]==false&&e[u][v]){
                e[u][v]=0;
                indegree[v]--;
            }
        }
    }
    int flag=0;
    while(!q.empty()){      //输出
        if(q.front()!=-1){
            if(!flag){
                cout<<q.front();
                q.pop();
                flag=1;
            }else{
                cout<<" ";
                cout<<q.front();
                q.pop();
            }
        }else{
            q.pop();
        }
    }
}
int main()
{
    fill(e[0],e[0]+maxn*maxn,0);
    cin>>n;
    cnt=n;
    indegree.resize(n);
    for(int i=0;i<n;i++){
        cin>>a[i];
    }
    for(int i=0;i<n;i++){
        if(a[i]==-1) continue;
        int index=a[i]%n;
        if(index!=i){
            indegree[i]=(i-index+n)%n;  //计算入度
            for(int j=0;j<indegree[i];j++)
                e[(index+j)%n][i]=1;   //计算连通的边
        }
    }
    topSort();
    return 0;
}

7-39 妈妈再也不用担心我被拖库啦! (25 分)

#include<iostream>
#include<string>
#include<map>
using namespace std;
struct Node{
	string c; //操作符记录
	string zh; //账号
	string mm; //密码
	string hx; //密码所对应的哈希值
};
int n;
Node node[1005];
map<string,pair<string,string> > mp;//已注册账号信息存储,map中第一个参数为账号,第二个参数为pair型,pair中第一个参数为密码,第二个参数为密码对应的哈希值。
char small_Hash(string str){ //计算字串的哈希值,返回一个字符char
	int sum=0;
	for(int i=0;i<str.length();i++){
		if(str[i]>='A'&&str[i]<='Z') str[i]=str[i]|32;
		if(str[i]>='0'&&str[i]<='9'){
			sum+=str[i]-'0';
		}else{
			sum+=str[i]-'a'+10;
		}
	}
	//cout<<"sum:"<<sum<<endl;
	sum=sum%36;
	if(sum<10) return sum+'0';
	else return sum-10+'a';
}
string Hash(string str){ //计算密码的哈希值,返回四位字符串
	string hx="0000";
	int l=str.length();
	int index[5]={0};
	for(int i=0;i<l%4;i++){
		index[i]++;
	}
	int j=0;
	for(int i=0;i<4;i++){
		index[i]+=l/4;
		string str1=str.substr(j,index[i]);
		//cout<<"str1:"<<i<<":"<<str1<<endl;
		j+=index[i];
		char h=small_Hash(str1);
		hx[i]=h;
	}
	return hx;
}
int main(void){
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>node[i].c>>node[i].zh>>node[i].mm;
		node[i].hx=Hash(node[i].mm);
		//cout<<node[i].hx<<endl;
		if(node[i].c=="R"){
			if(mp.find(node[i].zh)!=mp.end())cout<<"Repeated!"<<endl;
			else {
				mp[node[i].zh].first=node[i].mm;
				mp[node[i].zh].second=node[i].hx;
				cout<<"Signed!"<<endl;
			}
		}else if(node[i].c=="L"){
			if(mp.find(node[i].zh)==mp.end()){
				cout<<"Failed!"<<endl;
			}else{
				if(mp.find(node[i].zh)->second.first==node[i].mm) cout<<"Success!"<<endl;
				else{
					//cout<<mp.find(node[i].zh)->second.second<<"   "<<node[i].hx<<endl;
					if(mp.find(node[i].zh)->second.second==node[i].hx)cout<<"Attention!"<<endl;
					else cout<<"Failed!"<<endl;
				}
			}
		}
	}		
	return 0;
} 
//int main(void){ //检验字串哈希值计算
//	string str="sdf";
//	cout<<small_Hash(str);
//	return 0;
//}


7-40 Self-printable B+ Tree (35 分)

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

typedef struct node {
	struct node* left;
	int val[3];			//for nonleaf node, val[0] is the least key among its or its des' leaves
	struct node* mid;
	struct node* right;
	bool isleaf;
	int val_num;
	int ptr_num;
} Node;
typedef struct bptree {
	struct node* root;
	struct node* leaves;
} BpTree;

#define MAXKEYN 10005
#define EMP -1

Node* stack[MAXKEYN];
Node** stackptr = stack - 1;
bool push(Node* p) {
	if (stackptr == stack + MAXKEYN)return false;
	*(++stackptr) = p;
	return true;
}
Node* pop() {
	if (stackptr == stack - 1)return NULL;
	else return *(stackptr--);
}

Node* queue[MAXKEYN];
int front = 0;
int rear = -1;
bool EmptyQueue() {
	if (front == (rear + 1) % MAXKEYN)return true;
	else return false;
}
bool enqueue(Node* p) {
	if (front == (rear + 2) % MAXKEYN)return false;
	queue[++rear] = p;
	return true;
}
Node* dequeue() {
	if (EmptyQueue())return NULL;
	else return queue[front++];
}

void Arrange3(int a, int b, int c, Node* p) {
	int t;
	if (a < b) { t = a; a = b; b = t; }
	if (a < c) { t = a; a = c; c = t; }
	if (b < c) { t = b; b = c; c = t; }
	p->val[0] = c; p->val[1] = b; p->val[2] = a;
}
void Arrange4(int a, int b, int c, int d, Node* p, Node* q) {
	int t;
	if (a < b) { t = a; a = b; b = t; }
	if (a < c) { t = a; a = c; c = t; }
	if (a < d) { t = a; a = d; d = t; }
	if (b < c) { t = b; b = c; c = t; }
	if (b < d) { t = b; b = d; d = t; }
	if (c < d) { t = c; c = d; d = t; }
	p->val[0] = d; p->val[1] = c; q->val[0] = b; q->val[1] = a;
}
void InternalArrange3(Node* a, Node* b, Node* c, Node* par) {
	Node* t;
	if (a->val[0] < b->val[0]) { t = a; a = b; b = t; }
	if (a->val[0] < c->val[0]) { t = a; a = c; c = t; }
	if (b->val[0] < c->val[0]) { t = b; b = c; c = t; }
	par->left = c; par->mid = b; par->right = a;
}
void InternalArrange4(Node* a, Node* b, Node* c, Node* d, Node* par1, Node* par2) {
	Node* t;
	if (a->val[0] < b->val[0]) { t = a; a = b; b = t; }
	if (a->val[0] < c->val[0]) { t = a; a = c; c = t; }
	if (a->val[0] < d->val[0]) { t = a; a = d; d = t; }
	if (b->val[0] < c->val[0]) { t = b; b = c; c = t; }
	if (b->val[0] < d->val[0]) { t = b; b = d; d = t; }
	if (c->val[0] < d->val[0]) { t = c; c = d; d = t; }
	par1->left = d; par1->mid = c; par2->left = b; par2->mid = a;
}

bool Insert(int x, BpTree* tree_add);
bool InternalInsert(Node* new_child, Node* cur_node, BpTree* tree_add);
Node* Search(int x, BpTree tree);

int main(void)
{
	int n;
	scanf("%d", &n);
	int key[MAXKEYN] = { 0 };
	for (int i = 0; i < n; i++) {
		scanf("%d", &key[i]);
	}

	BpTree tree;
	tree.leaves = NULL;
	tree.root = NULL;
	for (int i = 0; i < n; i++) {
		if (!Insert(key[i], &tree))
			printf("Key %d is duplicated\n", key[i]);
	}

	int cnt = 1, node_num = 0;	// level order travesal
	Node* T;
	enqueue(tree.root);
	while (!EmptyQueue()) {
		T = dequeue();

		printf("[");
		if (T->isleaf) {	// is leaf, i from 0 to val_num-1
			for (int i = 0; i < T->val_num; i++) {
				if (i == T->val_num - 1)printf("%d", T->val[i]);
				else printf("%d,", T->val[i]);
			}
		}
		else {				// is internal node, i from 1 to ptr_num-1
			for (int i = 1; i < T->ptr_num; i++) {
				if (i == T->ptr_num - 1)printf("%d", T->val[i]);
				else printf("%d,", T->val[i]);
			}
		}
		printf("]");
		node_num += T->ptr_num;	//输出一个点后 node_num加上其子节点数 目的是得到下一层的节点个数
		cnt--;

		if (cnt == 0 /* && !T->isleaf */) {	// after outputting a level, need an enter
			printf("\n");				// but there's no enter at the end
			cnt = node_num;		//输出完一层后 cnt将从node_num开始递减 以确定下一层要输出多少个节点
			node_num = 0;		//node_num归零 以准备记录下下层的节点数
		}

		if (T->ptr_num >= 1) enqueue(T->left);
		if (T->ptr_num >= 2) enqueue(T->mid);
		if (T->ptr_num == 3) enqueue(T->right);
	}

	return 0;
}

bool Insert(int x, BpTree *tree_add)
{
	// if tree is empty
	if ((*tree_add).root == NULL) {
		(*tree_add).root = (*tree_add).leaves = (Node*)malloc(sizeof(Node));
		(*tree_add).root->isleaf = true;
		(*tree_add).root->val[0] = x;
		(*tree_add).root->val[1] = (*tree_add).root->val[2] = EMP;
		(*tree_add).root->val_num = 1;
		(*tree_add).root->left = (*tree_add).root->mid = (*tree_add).root->right = NULL;
		(*tree_add).root->ptr_num = 0;
		return true;
	}

	 //if x already exists
	Node* pos = Search(x, (*tree_add));
	if (pos)  return false;

	 //insert x
	// find the node where x should be
	Node* p = (*tree_add).root;
	while (!p->isleaf) {
		if (p->ptr_num == 2) {		// cur node has 1 sepa, stored in val1
			if (x < p->val[1]) { push(p); p = p->left; }
			else { push(p); p = p->mid; }
		}
		if (p->ptr_num == 3) {		// cur node has 2 sepa, stored in val1 and val2
			if (x < p->val[1]) { push(p); p = p->left; }
			else if (x >= p->val[1] && x < p->val[2]) { push(p); p = p->mid; }
			else { push(p); p = p->right; }
		}
	}
	// now, p points to the leaf node which x belongs to

	if (p->val_num == 1) {		// no need to split
		int t = p->val[0];
		p->val[0] = t > x ? x : t;
		p->val[1] = t > x ? t : x;
		p->val[2] = EMP;
		p->val_num++;
	}
	else if (p->val_num == 2) {	// no need to split
		Arrange3(p->val[0], p->val[1], x, p);
		p->val_num++;
	}
	else {						// need to split
		Node* q = (Node*)malloc(sizeof(Node));
		q->isleaf = true;
		q->left = q->mid = q->right = NULL;
		q->ptr_num = 0;
		q->right = p->right; p->right = q;	// insert q into the linked list of leaves 

		Arrange4(p->val[0], p->val[1], p->val[2], x, p, q);
		p->val_num = q->val_num = 2;

		Node* parent = pop();
		if (parent == NULL) {
			Node* newroot = (Node*)malloc(sizeof(Node));
			newroot->isleaf = false;
			newroot->val[0] = p->val[0];
			newroot->val[1] = q->val[0];
			newroot->val[2] = EMP;
			newroot->val_num = 2;
			newroot->left = p;
			newroot->mid = q;
			newroot->right = NULL;
			newroot->ptr_num = 2;

			(*tree_add).root = newroot;
		}
		else {
			InternalInsert(q, parent, tree_add);
		}
	}

	// update the vals of x's ancestors
	Node* ances;
	while (ances = pop()) {
		if (ances->ptr_num >= 1) ances->val[0] = ances->left->val[0];
		if (ances->ptr_num >= 2) ances->val[1] = ances->mid->val[0];
		if (ances->ptr_num == 3) ances->val[2] = ances->right->val[0];
	}

	return true;
}

// new_node is generated by cur_node splitting
bool InternalInsert(Node* new_child, Node* cur_node, BpTree *tree_add)
{

	if (cur_node->ptr_num == 1) {			// impossible to have just 1 ptr
	}
	else if (cur_node->ptr_num == 2) {	// no need to split
		InternalArrange3(cur_node->left, cur_node->mid, new_child,
			cur_node);
		cur_node->ptr_num++;
		// update the sepa
		cur_node->val[0] = cur_node->left->val[0];
		cur_node->val[1] = cur_node->mid->val[0];
		cur_node->val[2] = cur_node->right->val[0];
	}
	else {								// need to split
		Node* new_node = (Node*)malloc(sizeof(Node));
		new_node->isleaf = false;
		new_node->left = new_node->mid = new_node->right = NULL;
		new_node->ptr_num = 0;

		InternalArrange4(cur_node->left, cur_node->mid, cur_node->right, new_child,
			cur_node, new_node);
		cur_node->ptr_num = new_node->ptr_num = 2;
		// update the sepa
		cur_node->val[0] = cur_node->left->val[0];
		cur_node->val[1] = cur_node->mid->val[0];
		cur_node->val[2] = EMP;
		new_node->val[0] = new_node->left->val[0];
		new_node->val[1] = new_node->mid->val[0];
		new_node->val[2] = EMP;

		Node* parent = pop();
		if (parent == NULL) {	// recursion end (cur_node is root)
			Node* newroot = (Node*)malloc(sizeof(Node));
			newroot->isleaf = false;
			newroot->val[0] = cur_node->val[0];
			newroot->val[1] = new_node->val[0];
			newroot->val[2] = EMP;
			newroot->val_num = 2;
			newroot->left = cur_node;
			newroot->mid = new_node;
			newroot->right = NULL;
			newroot->ptr_num = 2;

			(*tree_add).root = newroot;
		}
		else {
			InternalInsert(new_node, parent, tree_add);
		}
	}

	return true;
}


Node* Search(int x, BpTree tree)
{
	Node* p = tree.leaves;
	while (p) {		
		if (p->val_num >= 1) {
			if (p->val[0] == x)return p;
		}
		if (p->val_num >= 2) {
			if (p->val[1] == x)return p;
		}
		if (p->val_num == 3) {
			if (p->val[2] == x)return p;
		}
		p = p->right;
	}
	return NULL;
}


7-41 凑零钱 (30 分)

#include <bits/stdc++.h>
using namespace std;
int n,m;
const int N = 1e4 + 10;
int a[N];

bool flag;
vector<int>ans;
void dfs(int sum,int u)
{
    if(flag)return;
    
    if(u == n + 1){
        return;
    }
    if(a[u] + sum > m){
        return;
    }
    else if(a[u] + sum == m){
        ans.push_back(a[u]);
        for(int i = 0;i < ans.size();i ++){
            if(i) cout << ' ';
            cout << ans[i];
        }
        flag = true;
        return;
    }else{
        ans.push_back(a[u]);
        dfs(a[u] + sum,u + 1);    
        ans.pop_back();
        dfs(sum,u + 1);
    }
}

int main()
{
    ios::sync_with_stdio(false);
    cin >> n >> m;
    int sum = 0;
    for(int i = 1;i <= n;i ++)
    {
         cin >> a[i];
         sum += a[i];
    }   
    if(sum < m){
        cout << "No Solution" << endl;
        return 0;
    }
    
    sort(a + 1,a + n + 1);
    while(a[n] > m){
        n --;
    }
    
    dfs(0,1);
    
    if(!flag){
        cout << "No Solution" << endl;
    }
    
    return 0;
}

7-42 矩阵链相乘问题 (20 分)

#include <bits/stdc++.h>
using namespace std;
const int MAX = 1005;
int p[MAX];
int m[MAX][MAX];
int n;
void  matrix()
{
    int i,j,r,k;
    memset(m,0,sizeof(m));
    for(r = 2; r<=n; r++)
    {
        for(i = 1; i<=n-r+1; i++)
        {
            j = i+r-1;
            m[i][j] = m[i+1][j]+p[i-1]*p[i]*p[j];
            for(k = i+1; k<j; k++)
            {
                int t = m[i][k] +m[k+1][j]+p[i-1]*p[k]*p[j];
                if(t<m[i][j])
                {
                    m[i][j] = t;
                }
            }
        }
    }
}
int main()
{
    cin>>n;
    for(int i=0; i<n+1; i++)
        cin>>p[i];
    matrix();
    cout<<m[1][n]<<endl;
    return 0;
}



7-43 真实的背包故事 (17 分)

#include <bits/stdc++.h>
using namespace std;
const int N = 110,M = 2100;

int dp[N][M][2];
int w[N],v[N];
int main()
{
    int n,m;
    
    cin >> n >> m;
    for(int i = 1;i <= n;i ++)
        cin >> w[i] >> v[i];
    
    for(int i = 1;i <= n;i ++){
        for(int j = 0;j <= m;j ++){
            dp[i][j][0] = dp[i - 1][j][0];
            dp[i][j][1] = dp[i - 1][j][1];
            if(j >= v[i]){
                if(dp[i - 1][j - v[i]][0] + w[i] > dp[i - 1][j][0]){
                    dp[i][j][0] = dp[i - 1][j - v[i]][0] + w[i];
                    dp[i][j][1] = dp[i - 1][j - v[i]][1] + 1;
                }else if(dp[i - 1][j - v[i]][0] + w[i] == dp[i - 1][j][0]){
                    dp[i][j][1] = min(dp[i - 1][j - v[i]][1] + 1,dp[i][j][1]);
                }
            }
        }
    }
    
    cout << dp[n][m][0] << ' ' << dp[n][m][1] << endl;
    
    
    
    return 0;
}

7-44 流水作业调度 (10 分)

#include <bits/stdc++.h>
using namespace std;
const int N = 110,M = 2100;

pair<int,int>p[N];
typedef pair<int,int> PII;

int main()
{
    int n;
    
    cin >> n;
    int s1 = 0,s2 = 0;
    vector<PII>v1,v2;
    
    /*
        1.分组
        2.把first < second 的放入到v1,否则放入v2
    */
    
    for(int i = 1;i <= n;i ++)
    {
        cin >> p[i].first >> p[i].second;
        if(p[i].first < p[i].second){
            v1.push_back({p[i].first,p[i].second});
        }else{
            v2.push_back({p[i].first,p[i].second});
        }
    }
    // v1 随便排序
    sort(v1.begin(),v1.end(),[](PII p1,PII p2){
        return p1.first < p2.first;
    });
    
    // v2 中按照升序排序
    sort(v1.begin(),v1.end(),[](PII p1,PII p2){
        return p1.second < p2.second;
    });
    
    vector<PII>vec;
    for(auto &x : v1){
        vec.push_back(x);
    }
    
    for(auto &x : v2){
        vec.push_back(x);
    }
    
    s1 += vec[0].first;
    s2 += vec[0].first + vec[0].second;
    
    for(int i = 1;i < vec.size();i ++){
        s1 += vec[i].first;
        if(s1 > s2){
            s2 = s1 + vec[i].second;
        }else{
            s2 = s2 + vec[i].second;    
        }
        
    }
    
    cout << s1 << ' ' << s2 << endl;
    
    return 0;
}

7-45 月饼 (25 分)

/*
注意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;
}



7-51 删数问题 (10 分)

#include <stdio.h>
#include <algorithm>
#include <cmath>
#include <string>
#include <string.h>
#include <iostream>
using namespace std;
int main()
{
    char a[105];
    int n;
    while(cin >> a >> n)
    {
        int m=strlen(a);
        while(n--)
        {
            int i=0;
            while(i<m-1&&a[i]<=a[i+1])
            {
                i++;
            }
            if(i==m-1)
            {
                m--;
                while(n--)
                   m--;
                break;
            }
            else
            {
                for(int j=i;j<m-1;j++)
                    a[j]=a[j+1];
                m--;
            }
        }
        for(int i=0;i<m;i++)
          printf("%c",a[i]);
        cout << endl;
    }
    return 0;
}
// https://blog.csdn.net/lvshubao1314/article/details/19673953

7-52 求解区间覆盖问题 (10 分)

#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.csdn.net/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;
}
  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值