ICPC-ACM 模板

1.最小覆盖(最大匹配模板)

(n*n)个图 k个边 求最小覆盖数

#include <stdio.h>
#include<string.h>
#include<algorithm>
#define N 1001
using namespace std;
int useif[N];   //记录y中节点是否使用 0表示没有访问过,1为访问过
int link[N];   //记录当前与y节点相连的x的节点
int mat[N][N]; //记录连接x和y的边,如果i和j之间有边则为1,否则为0
int gn,gm;    //二分图中x和y中点的数目
int can(int t)
{
    int i;
    for(i=1;i<=gm;i++)
    {
       if(useif[i]==0 && mat[t][i])
       {
           useif[i]=1;
           if(link[i]==-1 || can(link[i]))
           {
              link[i]=t;
              return 1;
           }
       }
    }
    return 0;
}

int MaxMatch()
{
    int i,num;
    num=0;
    memset(link,0xff,sizeof(link));
    for(i=1;i<=gn;i++)
    {
      memset(useif,0,sizeof(useif));
       if(can(i)) num++;
    }
    return num;
}

int main(int argc, char *argv[])
{
	int n,k;
	while(scanf("%d %d",&n,&k)!=EOF)
	{
		gn=gm=n;
		while(k--)
		{
			int c,d;
			scanf("%d %d",&c,&d);
			mat[c][d]=1;
		}			
		printf("%d\n",MaxMatch());
	} 
	return 0;
}

2.KM() 完美匹配  n*n 个边求收益最大的匹配

#include <iostream>
#include <cstring>
#include <cstdio>
#include<algorithm>
using namespace std;
const int MAXN = 305;
const int INF = 0x3f3f3f3f;
 
int love[MAXN][MAXN];   // 记录每个妹子和每个男生的好感度
int ex_girl[MAXN];      // 每个妹子的期望值
int ex_boy[MAXN];       // 每个男生的期望值
bool vis_girl[MAXN];    // 记录每一轮匹配匹配过的女生
bool vis_boy[MAXN];     // 记录每一轮匹配匹配过的男生
int match[MAXN];        // 记录每个男生匹配到的妹子 如果没有则为-1
int slack[MAXN];        // 记录每个汉子如果能被妹子倾心最少还需要多少期望值
int N;
bool dfs(int girl)
{
    vis_girl[girl] = true;
 
    for (int boy = 0; boy < N; ++boy) {
 
        if (vis_boy[boy]) continue; // 每一轮匹配 每个男生只尝试一次
 
        int gap = ex_girl[girl] + ex_boy[boy] - love[girl][boy];
 
        if (gap == 0) {  // 如果符合要求
            vis_boy[boy] = true;
            if (match[boy] == -1 || dfs( match[boy] )) {    // 找到一个没有匹配的男生 或者该男生的妹子可以找到其他人
                match[boy] = girl;
                return true;
            }
        } else {
            slack[boy] = min(slack[boy], gap);  // slack 可以理解为该男生要得到女生的倾心 还需多少期望值 取最小值 备胎的样子【捂脸
        }
    }
 
    return false;
}
 
int KM()
{
    memset(match, -1, sizeof match);    // 初始每个男生都没有匹配的女生
    memset(ex_boy, 0, sizeof ex_boy);   // 初始每个男生的期望值为0
 
    // 每个女生的初始期望值是与她相连的男生最大的好感度
    for (int i = 0; i < N; ++i) {
        ex_girl[i] = love[i][0];
        for (int j = 1; j < N; ++j) {
            ex_girl[i] = max(ex_girl[i], love[i][j]);
        }
    }
 
    // 尝试为每一个女生解决归宿问题
    for (int i = 0; i < N; ++i) {
 
        fill(slack, slack + N, INF);    // 因为要取最小值 初始化为无穷大
 
        while (1) {
            // 为每个女生解决归宿问题的方法是 :如果找不到就降低期望值,直到找到为止
 
            // 记录每轮匹配中男生女生是否被尝试匹配过
            memset(vis_girl, false, sizeof vis_girl);
            memset(vis_boy, false, sizeof vis_boy);
 
            if (dfs(i)) break;  // 找到归宿 退出
 
            // 如果不能找到 就降低期望值
            // 最小可降低的期望值
            int d = INF;
            for (int j = 0; j < N; ++j)
                if (!vis_boy[j]) d = min(d, slack[j]);
 
            for (int j = 0; j < N; ++j) {
                // 所有访问过的女生降低期望值
                if (vis_girl[j]) ex_girl[j] -= d;
 
                // 所有访问过的男生增加期望值
                if (vis_boy[j]) ex_boy[j] += d;
                // 没有访问过的boy 因为girl们的期望值降低,距离得到女生倾心又进了一步!
                else slack[j] -= d;
            }
        }
    }
 
    // 匹配完成 求出所有配对的好感度的和
    int res = 0;
    for (int i = 0; i < N; ++i)
        res += love[ match[i] ][i];
 
    return res;
}
 
int main()
{
	while(scanf("%d",&N)!=EOF)
	{
		int i,j;
		for(i=0;i<N;i++)
		{
			for(j=0;j<N;j++)
			{
				scanf("%d",&love[i][j]);
			}
		}
		
		printf("%d\n",KM());
	}
    return 0;
}        

3.模拟链表(从小到达插入一个数)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int a[105];
int main() {
	int data[101],right[101];
	int n,t,len,x;
	scanf("%d",&n);
	for(int i=1; i<=n; i++) scanf("%d",&data[i]);
	len=n;
	//初始化数组right
	for(int i=1; i<=n; i++) {
		if(i!=n) right[i]=i+1;
		else right[i]=0;
	}
	//直接在数组data的末尾增加一个数x,也就是data[len]
	len++;
	scanf("%d",&data[len]);
	//从链表头部开始遍历
	if(data[len]>=data[1] && data[len]<=data[len-1]) {
		t=1;
		while(t!=0) {
			if(data[right[t]]>data[len]) { //当发现第一个大于x的结点时,就说明x应该插入到这个数前面
				right[len]=right[t];//将x后面的结点设为第一个大于x的结点
				right[t]=len;//将一个大于x的结点前面的结点的下一个结点设为x
				break;
			}
			t=right[t];
		}
	}
	else if(data[len]<data[1]) cout<<data[len]<<" ";
	//输出链表的所有数
	t=1;
	while(t!=0) {
		printf("%d ",data[t]);
		t=right[t];
	}
	if(data[len]>data[len-1]) cout<<data[len];
	return 0;
}

4.Floyd+路径输出(求多源最短路)

#include <stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define inf 0x00ffffff
int map[200][200];
int path[200][200];
int tax[200];
int main(int argc, char *argv[])
{
    int n;
    while(scanf("%d",&n),n)
    {
        memset(path,0,sizeof(path));
        int i,j,k;
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=n;j++)
            {
                scanf("%d",&map[i][j]);
                if(map[i][j]!=-1)
                path[i][j]=j;
                else
                map[i][j]=inf;
            }
        }
        for(i=1;i<=n;i++)
        scanf("%d",&tax[i]);
        for(k=1;k<=n;k++)
        {
            for(i=1;i<=n;i++)
            {
                for(j=1;j<=n;j++)
                {
                    if(map[i][j]>map[i][k]+map[k][j]+tax[k])
                    {                                        
                        path[i][j]=path[i][k];
                        map[i][j]=map[i][k]+map[k][j]+tax[k];
                    }
                    else if(map[i][j]==(map[i][k]+map[k][j]+tax[k]))
                    {
                    	if(path[i][j]>path[i][k])
                        {
						path[i][j]=path[i][k];
                        map[i][j]=map[i][k]+map[k][j]+tax[k];
                        }
				    } 
                }
            }
        }
        int start,end;
        while(scanf("%d %d",&start,&end)!=EOF)
        {
            if(start==-1&&end==-1)
            break;
            printf("From %d to %d :\n",start,end);
            printf("Path: %d",start);
            int next=start;
            while(next!=end)
            {
            printf("-->%d",path[next][end]);
            next=path[next][end];
            }    
            printf("\n",end);        
            printf("Total cost : %d\n\n",map[start][end]);
        }
    }
    return 0;
}

5.Floyd(最小环)

#include <stdio.h>
#define inf 99999999
#include<algorithm>
using namespace std; 
int map[101][101];
int dis[101][101];
int main(int argc, char *argv[])
{
	int n,m;
	while(scanf("%d %d",&n,&m)!=EOF)
	{
		int i,j,k;
		for(i=0;i<=n;i++)
		{
			for(j=0;j<=n;j++)
			{
				map[i][j]=map[j][i]=dis[i][j]=dis[j][i]=inf;
			}
		}
		while(m--)
		{
			int a,b,c;
			scanf("%d %d %d",&a,&b,&c);
			map[a][b]=map[b][a]=dis[a][b]=dis[b][a]=min(map[a][b],c);
		}
		int min1=inf;
		for(k=1;k<=n;k++)
		{
			for(i=1;i<k;i++)
			{
				for(j=i+1;j<k;j++)
				{
					min1=min(min1,map[i][k]+map[k][j]+dis[i][j]);
				}
			}
			for(i=1;i<=n;i++)
			{
				for(j=1;j<=n;j++)
				{
					dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
				}
			}
		}
		if(min1>=inf)
		{
			printf("It's impossible.\n");
		}
		else
		printf("%d\n",min1);
	}
	return 0;
}

6.给出一个图,要求出最大的pseudoforest, 所谓pseudoforest就是指这个图的一个子图,这个子图的每个连通分量中最多只能有一个环, 而且这个子图的所有权值之和最大。这个就是所谓的伪森林。

#include <stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int bin[100010],flag;
long long sum;
struct node{
	int s,e,w;
}a[100001];
int judge[100001];
int findx(int x)
{
	return bin[x]==x?x:bin[x]=findx(bin[x]);
}
int merge(int a,int b,int c)
{
	int fx=findx(a);
	int fy=findx(b);
	if(fx!=fy)
	{
		if(judge[fx]&&judge[fy])
		return 0;
		bin[fy]=fx;
		sum+=c;
		if(judge[fx]||judge[fy])
		judge[fx]=1;
	}
	else if(fx==fy&&!judge[fx])
	{
		judge[fx]=1;
		sum+=c;
	}
}
int cmp(node a,node b)
{
	return a.w>b.w;
}
int main(int argc, char *argv[])
{
	int n,m;
	while(scanf("%d %d",&n,&m),m+n)
	{
		int i;
		memset(judge,0,sizeof(judge));
		for(i=0;i<n;i++)
		{
			bin[i]=i;
		}
		for(i=0;i<m;i++)
		{
			scanf("%d %d %d",&a[i].s,&a[i].e,&a[i].w);
		}
		sort(a,a+m,cmp);
		sum=0;
		for(i=0;i<m;i++)
		{
			merge(a[i].s,a[i].e,a[i].w);
		}
		printf("%lld\n",sum);
	}
	return 0;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1 图论 3 1.1 术语 3 1.2 独立集、覆盖集、支配集之间关系 3 1.3 DFS 4 1.3.1 割顶 6 1.3.2 桥 7 1.3.3 强连通分量 7 1.4 最小点基 7 1.5 拓扑排序 7 1.6 欧拉路 8 1.7 哈密顿路(正确?) 9 1.8 Bellman-ford 9 1.9 差分约束系统(用bellman-ford解) 10 1.10 dag最短路径 10 1.11 二分图匹配 11 1.11.1 匈牙利算法 11 1.11.2 KM算法 12 1.12 网络流 15 1.12.1 最大流 15 1.12.2 上下界的网络的最大流 17 1.12.3 上下界的网络的最小流 17 1.12.4 最小费用最大流 18 1.12.5 上下界的网络的最小费用最小流 21 2 数论 21 2.1 最大公约数gcd 21 2.2 最小公倍数lcm 22 2.3 快速幂取模B^LmodP(O(logb)) 22 2.4 Fermat小定理 22 2.5 Rabin-Miller伪素数测试 22 2.6 Pollard-rho 22 2.7 扩展欧几里德算法extended-gcd 24 2.8 欧拉定理 24 2.9 线性同余方程ax≡b(mod n) 24 2.10 中国剩余定理 25 2.11 Discrete Logging(BL == N (mod P)) 26 2.12 N!最后一个不为0的数字 27 2.13 2^14以内的素数 27 3 数据结构 31 3.1 堆(最小堆) 31 3.1.1 删除最小值元素: 31 3.1.2 插入元素和向上调整: 32 3.1.3 堆的建立 32 3.2 并查集 32 3.3 树状数组 33 3.3.1 LOWBIT 33 3.3.2 修改a[p] 33 3.3.3 前缀和A[1]+…+A[p] 34 3.3.4 一个二维树状数组的程序 34 3.4 线段树 35 3.5 字符串 38 3.5.1 字符串哈希 38 3.5.2 KMP算法 40 4 计算几何 41 4.1 直线交点 41 4.2 判断线段相交 41 4.3 三点外接圆圆心 42 4.4 判断点在多边形内 43 4.5 两圆交面积 43 4.6 最小包围圆 44 4.7 经纬度坐标 46 4.8 凸包 46 5 Problem 48 5.1 RMQ-LCA 48 5.1.1 Range Minimum Query(RMQ) 49 5.1.2 Lowest Common Ancestor (LCA) 53 5.1.3 Reduction from LCA to RMQ 56 5.1.4 From RMQ to LCA 57 5.1.5 An<O(N), O(1)> algorithm for the restricted RMQ 60 5.1.6 An AC programme 61 5.2 最长公共子序列LCS 64 5.3 最长上升子序列/最长不下降子序列(LIS) 65 5.3.1 O(n^2) 65 5.3.2 O(nlogn) 66 5.4 Joseph问题 67 5.5 0/1背包问题 68 6 组合数学相关 69 6.1 The Number of the Same BST 69 6.2 排列生成 71 6.3 逆序 72 6.3.1 归并排序求逆序 72 7 数值分析 72 7.1 二分法 72 7.2 迭代法(x=f(x)) 73 7.3 牛顿迭代 74 7.4 数值积分 74 7.5 高斯消元 75 8 其它 77
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值