NOIP初赛相关代码

Sort

 void Sort(int a[], int L, int R) {
    if (L >= R) return ;
    int x = a[L], i = L, j = R;
    while (i != j) {
        while (i != j && a[j] >= x) j--;
            a[i] = a[j];
        while (i != j && a[i] <= x) i++;
            a[j] = a[i];
    }
    a[i] = x;
    Sort(a, L, i-1);
    Sort(a, i+1, R);
}    

最短路径

INPUT:
输入包括多组数据。每组数据第一行是两个整数N、M(N<=100,M<=10000),N表示节点数,标号为1的节点是起点,标号为N的节点是终点,M则表示有几条路。N=M=0表示输入结束。接下来M行,每行包括3个整数A,B,C(1<=A,B<=N,1<=C<=1000),表示在节点A与节点B之间有一条路,长度为C输入保证至少存在1条可行路线
OUTPUT:
对于每组输入,输出一行,表示从起点到终点的最短路程

Floyd

void Floyed() {
    for (int k=1; k<=n; k++)            //中介点要放在最外层 
        for (int i=1; i<=n; i++) if (i != k)
            for (int j=1; j<=n; j++) if (j != k && j != i)
                if (mp[i][j] > mp[i][k] + mp[k][j])
                    mp[i][j] = mp[i][k] + mp[k][j];
}

Dijkstra+邻接矩阵

#include<bits/stdc++.h>
using namespace std;
const int N = 107;
const int M = 10007;
int mp[N][N], n, m;
int dis[N];         //dis[i]表示起点与点i的距离 
bool mark[N];
void Dijkstra(int st, int ed) {
    memset(dis, 127/3, sizeof(dis));
    memset(mark, false, sizeof(mark));
    dis[st] = 0;
    while (1) {
        int p = 0;
        for (int i=1; i<=n; i++)        
            //在所有未确定的点中找与起点路径最短的点作为确定点(贪心法) 
            if (!mark[i] && dis[i] < dis[p]) p = i;
        if (!p || p == ed) break;
        //若起点与所有与起点联通的点的最短路都已找到(p==0),或终点被找到(p==ed),就退出循环 
        mark[p] = true;                 //将p点设置为已确定 
        for (int i=1; i<=n; i++)        //用p点更新与p点相连的点的最短路 
            if (!mark[i] && dis[i] > dis[p] + mp[p][i])     
            //加上 !mark[i] 可稍微提高一点效率 
                dis[i] = dis[p] + mp[p][i];
    }
}
int main()
{
    while (scanf("%d %d", &n, &m) && n && m) {
        memset(mp, 127/3, sizeof(mp));
        int u, v, w, st = 1, ed = n;
        while (m--) {
            scanf("%d %d %d", &u, &v, &w);
            mp[u][v] = mp[v][u] = w;
        }
        Dijkstra(st, ed);
        printf("%d\n", dis[ed]);
    }   
    return 0;
}

Dijkstra+邻接表+队列优化

#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int N = 1007;
const int M = 10007;
struct Edge {
    int to, val, next;
}e[M << 1];
int head[N], dis[N], n, m, cnt;
bool mark[N];
struct cmp{
    bool operator ()(const int &a, const int &b) {
        return dis[a] > dis[b];         //定义">",建立小顶堆 
    }
};
priority_queue <int, vector<int>, cmp> q;   //定义优先队列,自定义排序规则cmp 
void addedge(int u, int v, int w) {
    e[++cnt].to = v;
    e[cnt].val = w;
    e[cnt].next = head[u];
    head[u] = cnt;
}
void Dijkstra(int st, int ed) {
    memset(dis, 127/3, sizeof(dis));
    memset(mark, false, sizeof(mark));
    while (!q.empty()) q.pop();     //清空队列
    dis[st] = 0;
    q.push(1);
    while (1) {
        //因为同一个点可能多次入队,所以队列中的点可能已是确定点 
        //如遇到确定点,就出队丢弃 
        while (!q.empty() && mark[q.top()]) q.pop();    
        if (q.empty()) break;       //队列为空表示与起点联通的点的最短路均已确定 
        int p = q.top();
        q.pop();
        if (p == ed) break;         //与终点的最短路已找到 
        mark[p] = true;
        for (int i=head[p]; i; i=e[i].next)
            if (!mark[e[i].to] && dis[e[i].to] > dis[p] + e[i].val) {
                dis[e[i].to] = dis[p] + e[i].val;
                q.push(e[i].to);            //将距离有变化的点入队 
            }               
    } 
}
int main() {
    freopen("data.in", "r", stdin);
    while (scanf("%d %d", &n, &m) && n && m) {
        memset(e, 0, sizeof(e));
        memset(head, 0, sizeof(head));
        cnt = 0;
        int u, v, w, st = 1, ed = n;
        while (m--) {
            scanf("%d %d %d", &u, &v, &w);
            addedge(u, v, w);
            addedge(v, u, w);
        }
        Dijkstra(st, ed);
        printf("%d\n", dis[ed]);
    }   
    return 0;
}

SPFA

O(kE) E是边数,k是常数,平均值为2 
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int N = 107;
const int M = 10007;
struct Edge {
    int to, val, next;
}e[M << 1];
int head[N], dis[N], pre[N], n, m, cnt;
int times[N];           //统计入队次数,若某点入队次数达到n次,表示该图有负权环 
bool exist[N];          //设置exist[],是为了避免重复入队 
void addedge(int u, int v, int w) {
    e[++cnt].to = v;
    e[cnt].val = w;
    e[cnt].next = head[u];
    head[u] = cnt;
}
queue <int> q;
int SPFA(int st) {          //返回值为True表示不存在负权环,反之存在 
    memset(dis, 127/3, sizeof(dis));
    memset(exist, false, sizeof(exist));
    memset(times, 0, sizeof(times));
    dis[st] = 0;        //设置起点 
    q.push(st);         //起点入队 
    exist[st] = true;   //标志起点已入队 
    times[st]++;
    while (!q.empty()) {
        int p = q.front();      //从队中取出一个节点 
        q.pop(); 
        exist[p] = false;
        for (int i=head[p]; i; i=e[i].next)     //遍历与此节点相邻的边,对与之相邻的点更新 
            if (dis[e[i].to] > dis[p] + e[i].val) {
                dis[e[i].to] = dis[p] + e[i].val;
                pre[e[i].to] = p;               //记录路径:e[i].to的前一个节点是p 
                if (!exist[e[i].to]) {          //如有节点被更新,则将该点入队,以便更新其他点 
                    q.push(e[i].to);
                    exist[e[i].to] = true;
                    times[e[i].to]++;
                    if (times[e[i].to] >= n) return false;      //检查是否存在负权环 
                }
            }               
    }
    return true;
}
void print(int p) {
    if (pre[p]) print(pre[p]);
    else {printf("%d", p); return;  }
    printf("->%d", p);
}
int main()
{
    freopen("data.in", "r", stdin);
    while (scanf("%d %d", &n, &m) && n && m) {
        memset(e, 0, sizeof(e));
        memset(head, 0, sizeof(head));
        cnt = 0;
        int u, v, w, st = 1, ed = n;
        while (m--) {
            scanf("%d %d %d", &u, &v, &w);
            addedge(u, v, w);
            addedge(v, u, w);
        }
        if (SPFA(st)) {
            printf("%d\n", dis[ed]);
        //  print(ed);              //输出路径 
        //  printf("\n");
        }       
    }   
    return 0;
}

最小生成树

Kruskal
n(n<=100)个节点 f(i,j)表示i,j之间路径长度(f(i,j)<=1000) ,f(i,j)为0表示i,j之间无路径 ,要使每一个节点均连通.求Σf(i,j)min
INPUT:第一行两个正整数n k,接下来的k行每行三个正整数i j m
OUTPUT:一行,Σf(i,j)min

#include<bits/stdc++.h>
using namespace std;
struct Edge{
    int u,v,w;
}e[11000];
int cnt=0,n,tot=0,ans=0,sum=0;
int a,i,j,k,x,y,w;
int fa[1000]={0};
bool cmp(Edge a,Edge b){
    return a.w<b.w;
}
int find(int x){
    if(fa[x]==x)return fa[x];
    else return fa[x]=find(fa[x]);
}
void Together(int x,int y){
    int fx=find(x);
    int fy=find(y);
    fa[fx]=fy;
}
int main(){
    scanf("%d%d",&n,&k);
    for(i=1;i<=k;i++)fa[i]=i;
    for(i=1;i<=k;i++){
        scanf("%d %d %d",&x,&y,&w);
        e[i].u=x; e[i].v=y; e[i].w=w;
    }
    sort(e+1,e+k+1,cmp);
    int T=0;
    for(i=1;i<=k;i++){
        x=e[i].u;y=e[i].v;
        int fx,fy;
        fx=find(x);fy=find(y);
        if(fx!=fy){
            Together(x,y);
            tot+=e[i].w;
            T++;
        }
        if(T==n-1)break;
    }
    printf("%d",tot);
    return 0;
}

LCA(最近公共祖先)

#include <bits/stdc++.h>
using namespace std;
const int N = 50007;
const int M = 75007;
struct Edge{
    int to, w, next;
}e[N<<1];
int n, head[N], cnt, fa[N][20], dis[N], deep[N];
void addedge(int u, int v, int w){
    e[++cnt].to = v; e[cnt].w = w; e[cnt].next = head[u]; head[u] = cnt;
}
void dfs(int cur, int father, int w){   //dfs函数:先处理cur的所有信息,再往下递归 
    deep[cur] = deep[father] + 1 ;      //cur的深度(根节点的深度设为1)      
    dis[cur] = dis[father] + w;         //cur到根节点的距离 
    fa[cur][0] = father;                //cur的父节点(没有父亲就等于0,根节点的父亲就是0)
    for (int i=1; i<16; i++) {          //由于cur的祖先的fa[]都已经计算完毕,所以可以用来计算cur的各级祖先 
        if (!fa[cur][i-1]) break;       //如果cur没有2^(i-1)级祖先,自然不会有更高级的祖先,直接break 
        fa[cur][i] = fa[fa[cur][i-1]][i-1];
    }
    for (int i=head[cur]; i; i=e[i].next)
        if (e[i].to != father) dfs(e[i].to, cur, e[i].w);
        //同时存在u->v与v->u二条边 
}
int LCA(int u, int v){
    if (deep[u] < deep[v]) swap(u, v);  //深度大的为u 
    int k = deep[u] - deep[v];          //k等于u与v的深度差 
    for (int i=0; i<=16; i++)           //此循环用于提到深度相同。
        if (1<<i & k) u = fa[u][i];
    if (u == v) return v;               //u等于v说明v是u的祖先,也就是它们的LCA 
    for (int i=16; i>=0; i--)           //u与v一起上升,此处循环必须是从大到小!
        if (fa[u][i] != fa[v][i]){      //因为我们应该越提越“精确”,这是关键 
            u = fa[u][i];
            v = fa[v][i];
        }
    return fa[u][0];            //此时u、v的第一个父亲就是LCA。
}
int main()
{
    //freopen("data.in", "r", stdin);
    int m, u, v, w;
    scanf("%d", &n);
    for (int i=1; i<n; i++){
        scanf("%d %d %d", &u, &v, &w);
        u++; v++;
        addedge(u, v, w);
        addedge(v, u, w);
    }
    dfs(1, 0, 0);
    scanf("%d", &m);
    while (m--) {
        scanf("%d %d", &u, &v);
        u++; v++;
        printf("%d\n", dis[u] + dis[v] - 2*dis[LCA(u, v)]); 
    }   
    return 0;
}

二分图

二分图最大匹配(匈牙利算法)

#include <bits/stdc++.h>
using namespace std;
const int N = 507;
bool mp[N][N], vis[N];
//将二分图分成左图和右图,与右点匹配的左点记录在match[]中
int match[N], n, m;
bool dfs(int u){
    for (int v=1; v<=m; v++)        //遍历与左点u的相邻的右点v 
        if (mp[u][v] && !vis[v]){   //若u、v相连,且v不在交替路中 
            vis[v] = true;          //将v加入交替路 
            if (!match[v] || dfs(match[v])){    //若v未匹配或者v的匹配点存在增广路(递归),即找到增广路 
                match[v] = u;       //修改匹配 
                return true;
            }
        }
    return false;
}
int main()
{
    freopen("data.in", "r", stdin);
    int k;
    while (scanf("%d", &k) && k){
        int u, v, cnt = 0;
        memset(mp, false, sizeof(mp));
        memset(match, 0, sizeof(match));
        scanf("%d %d", &n, &m);
        while (k--){
            scanf("%d %d", &u, &v);
            mp[u][v] = true;
        }
        //依次给每一个左点找匹配点(增广路),若找到,cnt++ 
        //这里隐含一个事实:在给当前点找匹配点的过程中,不会更改其他点的匹配状态
        //即cnt的变化只取决于当前点是否找到匹配点 
        for (int i=1; i<=n; i++){
            memset(vis, false, sizeof(vis));
            if (dfs(i)) cnt++;
        }           
        printf("%d\n", cnt);
    }
    return 0;
}

二分图最优匹配(KM算法)

#include <bits/stdc++.h>
using namespace std;
const int N = 307;
bool visx[N], visy[N];
int n, a[N], b[N], w[N][N], match[N];   
//a[]、b[]分别为左点和右点的标号,w[i][j]为i到j的权,
//match[i] = j 表示右点i与左点j匹配 
bool dfs(int u){                //给u找匹配 
    visx[u] = true;
    for (int v = 1; v <= n; v++)
        if (!visy[v] && a[u] + b[v] == w[u][v]){
            //满足 a[u] + b[v] == w[u][v] 才能加入 
            visy[v] = true;
            if (!match[v] || dfs(match[v])){
                match[v] = u;
                return true;
            }
        }
    return false;
}
int KM(){
    //初始化a[] = max, b[] = 0, match[] = 0
    memset(b, 0, sizeof(b));
    for (int u = 1; u <= n; u++){
        a[u] = w[u][1];
        for (int v = 2; v <= n; v++)
            a[u] = max(a[u], w[u][v]);
    }
    memset(match, 0, sizeof(match));
    //给每个左点找最佳匹配 
    for (int u = 1; u <= n; u++){
        while (1){      //可能需要多次才能找到 
            memset(visx, false, sizeof(visx));
            memset(visy, false, sizeof(visy));
            if (dfs(u)) break;      //若找到匹配,就找下一个 
            //若未找到匹配, 就计算d值 
            int d = 0x7fffffff;      
            for (int i = 1; i <= n; i++) if (visx[i])   
            //本轮匹配涉及到的左点 
                for (int j = 1; j <= n; j++) if (!visy[j])  
                //本轮匹配未涉及到的右点 
                    d = min(d, a[i] + b[j] - w[i][j]);
            //修改标号,左点减、右点加 
            for (int i = 1; i <= n; i++)
                if (visx[i]) a[i] -= d;
            for (int i = 1; i <= n; i++)
                if (visy[i]) b[i] += d;
        }
    }
    //统计各匹配的权值之和 
    int ret = 0;
    for (int v = 1; v <= n; v++)
        ret += w[match[v]][v];
    return ret; 
}
int main()
{
    freopen("data.in", "r", stdin);
    while (~scanf("%d", &n)) {
        memset(w, 0, sizeof(w));        
        for (int u = 1; u <= n; u++)
            for (int v = 1; v <= n; v++)
                scanf("%d", &w[u][v]);
        printf("%d\n", KM());       //KM()返回最佳匹配的权值之和 
    }
    return 0;
}
天梯(tianti) Java 轻量级的 CMS 解决方案-天梯。天梯是一个用 Java 相关技术搭建的后台 CMS 解决方案,用户可以结合自身业务进行相应扩展,同时提供了针对 dao、service 等的代码生成工具。技术选型:Spring Data JPA、Hibernate、Shiro、 Spring MVC、Layer、MySQL 等。 简介: 1、天梯是一款使用Java编写的免费的轻量级CMS系统,目前提供了从后台管理到前端展现的整体解决方案。 2、用户可以不编写一句代码,就制作出一个默认风格的CMS站点。 3、前端页面自适应,支持PC和H5端,采用前后端分离的机制实现。后端支持天梯蓝和天梯红换肤功能。 4、项目技术分层明显,用户可以根据自己的业务模块进行相应地扩展,很方便二次开发。 核心框架:Spring Framework 4.2.5.RELEASE 安全框架:Apache Shiro 1.3.2 视图框架:Spring MVC 4.2.5.RELEASE 数据库连接池:Tomcat JDBC 缓存框架:Ehcache ORM框架:Spring Data JPA、hibernate 4.3.5.Final 日志管理:SLF4J 1.7.21、Log4j 编辑器:ueditor 工具类:Apache Commons、Jackson 2.8.5、POI 3.15 view层:JSP 数据库:mysql、oracle等关系型数据库 前端 dom : Jquery 分页 : jquery.pagination UI管理 : common UI集成 : uiExtend 滚动条 : jquery.nicescroll.min.js 图表 : highcharts 3D图表 :highcharts-more 轮播图 : jquery-swipe 表单提交 :jquery.form 文件上传 :jquery.uploadify 表单验证 :jquery.validator 展现树 :jquery.ztree html模版引擎 :template
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值