目 录

  • 2013-12
    • 出现次数最多的数
    • ISBN号码
    • 最大的矩形
    • 有趣的数
    • I‘m stuck!⭐
  • 2014-03
    • 相反数
    • 窗口
    • 命令行选项
    • 无线网络
    • 任务调度⭐
  • 2014-09
    • 相邻数对
    • 画图
    • 字符串匹配
    • 最优配餐
    • 拼图⭐
  • 2014-12
    • 门禁系统
    • Z字形扫描
    • 集合竞价
    • 最优灌溉
    • 货物调度
  • 2015-03
    • 图像旋转
    • 数字排序
    • 节日
    • 网络延时
    • 最小花费
  • 2015-09
    • 数列分段
    • 日期计算
    • 模板生成系统
    • 高速公路
    • 最佳文章
  • 2015-12
    • 数位之和
    • 消除类游戏
    • 画图
    • 送货
    • 矩阵

2013-12

出现次数最多的数


题解:此题用hash表进行统计

#define _CRT_SECURE_NO_WARNINGS 1
#include<cstdio>
#include<cstring>
#include<stack>
#include<algorithm>
#include<iostream>
#include<string>
#include<set>
using namespace std;
const int maxn = 10010;
int hashtable[maxn] = { 0 };
int main() {int n;int i;int num;scanf("%d", &n);for (i = 0; i < n; i++){scanf("%d",&num);hashtable[num]++;}int max = 0;for (i = 0; i < maxn; i++){if (hashtable[i] > hashtable[max])max = i;}printf("%d",max);return 0;
}

ISBN号码


题解:正常的字符串处理,注意字符串取大点

#define _CRT_SECURE_NO_WARNINGS 1
#include<cstdio>
#include<cstring>
#include<stack>
#include<algorithm>
#include<iostream>
#include<string>
#include<set>
using namespace std;
int main() {char a[15];scanf("%s",a);int num=0;//计算正确的识别码int temp = 1;for (int i = 0; i <= 10; i++){if (i != 1 && i != 5){num += (a[i] - '0') * temp;temp++;}}num %= 11;if (num != 10){if (num == a[12] - '0'){printf("Right");}else{a[12] = num + '0';printf("%s", a);}}else{if (a[12] == 'X'){printf("Right");}else{a[12] ='X';printf("%s", a);}}return 0;
}

最大的矩形


题解:这题考察的是动态规划
一共有n个矩形,S[i][j]表示坐标i到坐标j之间最大的矩形面积,注意坐标i从1开始,一直到n,j从i+1开始,一直到n+1结束;
初始条件:S[i][i+1]=h[i]

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<stdio.h>
#include<string>
#include<cstring>
#include<cmath>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<limits>
using namespace std;
//最大的矩形
const int maxn=1010;
int S[maxn][maxn];//S[i][j]表示下标i到下标j之间的最大矩形面积
int h[maxn];//h[1]-h[n]
int main()
{int i, j;int n;scanf("%d",&n);for (int i = 1; i <= n; i++){scanf("%d",&h[i]);}int minh;int maxlen;for (int i = 1; i <= n; i++){minh = h[i];maxlen = 1;S[i][i + 1] = h[i];for (int j = i+2; j <= n+1; j++){if (h[j-1] >= minh){maxlen++;S[i][j] = minh * maxlen;}             else{minh = h[j-1];maxlen++;S[i][j] = max(S[i][j-1], minh * maxlen);}           }}int maxS = -1;for (int i = 1; i <= n; i++){for (int j = i + 1; j <= n+1; j++){           if (S[i][j] > maxS)maxS = S[i][j];}}printf("%d",maxS);return 0;
}

有趣的数


题解:这题还是考的动态规划鸭
status[i][j]表示长度为i状态为j的有趣的数个数
已知有趣的数一共有五种状态
整个字符串只有一个字符:由题意知这个字符只能是2
状态0:有2
整个字符串有两个字符:
状态1:有2、0
状态2:有2、3;且3在2后面
整个字符串有3个字符
状态3:有2、0、1;且1在0后面
状态4:有2、3、0;且3在2后面
整个字符串有4个字符:
状态5:有2、3、0、1;且3在2后面,1在0后面

下面可以知道
初始条件:

dp[1][0]=1;
dp[1][1]=0;
dp[1][2]=0;
dp[1][3]=0;
dp[1][4]=0;
dp[1][5]=0;

下面i从2到n迭代,最后dp[i][5]即为结果,迭代式子如下:

dp[i][0]=1;//显而易见
//只有2,长度为i-1的字符串在后面加上0
//有2,0,长度为i-1的字符串在后面加上2或则和0,所以要*2
dp[i][1]=dp[i-1][0]+2*dp[i-1][1];
//只有2,长度为i-1的字符串在后面加上3
//有2,3,长度为i-1的字符串,因为2只能在3前面,所以只能在i-1字符串后面加上3
dp[i][2]=dp[i-1][0]+dp[i-1][2];
//只有2、0,长度为i-1的字符串在后面加上1
//有2,0,1,长度为i-1的字符串,面加上2或者1
dp[i][3]=dp[i-1][1]+dp[i-1][3]*2;
//有2,0,长度为i-1的字符串在后面加上3
//有2,3,长度为i-1的字符串在后面加上0
//有2,0,3的字符串在后面加上3或者0
dp[i][4]=dp[i-1][1]+dp[i-1][2]+dp[i-1][4]*2;
//有2、0、1、3的字符串在后面加上1或者3
//和上面一样,类推
//和上面一样,类推
dp[i][5]=dp[i-1][5]*2+dp[i-1][3]+dp[i-1][4];

因为要模MOD=1000000007
所以每次计算dp都%MOD

同时注意dp数组开成long long

/* CCF201312-4 有趣的数 */#include <iostream>
#include <cstring>
using namespace std;
const long long MOD = 1000000007;
const int MAXN = 1000;
const int MAXS = 5;
long long status[MAXN+1][MAXS+1]; int main()
{int n; cin >> n; memset(status, 0, sizeof(status)); // DPstatus[1][0] = 1;for(int i=2; i<=n; i++) {status[i][0] = 1;status[i][1] = (status[i - 1][1] * 2 + status[i - 1] [0]) % MOD;status[i][2] = (status[i - 1][2] + status[i - 1][0]) % MOD;status[i][3] = (status[i - 1][3] * 2 + status[i - 1][1] ) % MOD;status[i][4] = (status[i - 1][4] * 2 + status[i - 1][1] + status[i - 1][2]) % MOD;status[i][5] = (status[i - 1][5] * 2 + status[i - 1][3] + status[i - 1][4]) % MOD;} cout << status[n][5] << endl; return 0;
}

I‘m stuck!⭐


题解:这题目前的思路是两次BFS广度优先搜索,开数组进行记录,最后会和

2014-03

相反数


题解:同样的hashtable计数

#define _CRT_SECURE_NO_WARNINGS 1
#include<cstdio>
#include<cstring>
#include<stack>
#include<algorithm>
#include<iostream>
#include<string>
#include<set>
using namespace std;
const int maxn = 1010;
int hashtable[maxn] = {0};
int main() {int n, i;int num ;  scanf("%d",&n);for (i = 0; i < n; i++){     scanf("%d", &num);hashtable[abs(num)]++;}num = 0;//表示一共有多少对for (i = 0; i < maxn; i++){if (hashtable[i] == 2)num++;}  printf("%d",num);return 0;
}

窗口

#define _CRT_SECURE_NO_WARNINGS 1
#include<cstdio>
#include<cstring>
#include<stack>
#include<algorithm>
#include<iostream>
#include<string>
#include<set>
using namespace std;
struct Window
{int cengci;//cengci=n说明在最上面int id;//id表示编号int x1;int x2;int y1;int y2;
}win[12];//最多10个窗口
bool cmp(Window a, Window b)
{return a.cengci < b.cengci;
}
int main() {int n, m;int i;int tempx, tempy;int j;scanf("%d %d", &n, &m);for (i = 1; i <=n; i++){scanf("%d %d %d %d", &win[i].x1, &win[i].y1, &win[i].x2, &win[i].y2);win[i].id = i;win[i].cengci = i;//}int tempcengci;int tempid;for (i = 1; i <= m; i++){tempcengci = 0;sort(win+1, win +1+ n, cmp);//注意sort是怎么写的        scanf("%d %d",&tempx,&tempy);for (j = n; j >=1; j--)//从cengci由大到小,即从最上面开始选{if (win[j].x1 <= tempx && win[j].y1 <= tempy && win[j].x2 >= tempx && win[j].y2 >= tempy){printf("%d\n",win[j].id);//如果选到了,就把之前的id输出tempcengci = win[j].cengci;tempid = win[j].id;win[j].cengci = n;//排在最前面break;}}if (tempcengci == 0){printf("IGNORED\n");}else{for (j = n; j >= 1; j--)//从cengci由大到小,即从最上面开始选{if(win[j].cengci > tempcengci&&win[j].id!=tempid)win[j].cengci--;}}}return 0;
}

命令行选项


这道题目第一次做20分,第二次做40分,下面是参考了的满分答案,注释很清楚

#define _CRT_SECURE_NO_WARNINGS 1
#include<cstdio>
#include<cstring>
#include<stack>
#include<algorithm>
#include<iostream>
#include<string>
#include<set>
#include<map>
#include<vector>
//这道题目有几个很重要的思想:
/*
* 1、将输入的一行string字符按照空格分开单独存储在vector<string>中用vector的迭代器it来取vecotr里面的string模板如下:for (pos = line.find(" "); pos != -1; pos = line.find(" ")){ve.push_back(line.substr(0,pos));line = line.substr(pos+1);}ve.push_back(line);* 2、题目说按照升序输出,并且后出现的参数可以覆盖前面的参数,map可以完美实现这个要求
* ①map自动按照key进行升序排序
* ②map的key对应唯一值,可以实现后来覆盖
*
* 3、不用急着将命令存到某个数据结构里面,就让它们在str里面呆着
* 用的时候使用find来判断是不是命令,以及带不带参数
*
* 4、要注意进行边界检查
*/
using namespace std;
string str;
string str1;
string line;
int n;
int pos;
vector<string> ve;
map<char, string> ans;//最终的映射结果,map会以键值从小到大自动排序
int main() {cin >> str;cin >> n;getline(cin,str1);//吸收换行符   for (int i = 1; i <= n; i++){ve.clear();ans.clear();getline(cin,line);//输入Line//第一步.将每一行根据空格存储在vector ve中for (pos = line.find(" "); pos != -1; pos = line.find(" ")){ve.push_back(line.substr(0,pos));line = line.substr(pos+1);}   ve.push_back(line);/*第二步.判断数据是否合法,不合法直接break合法则装入map若有参数,则装入参数*/vector<string>::iterator it;for (it = ve.begin()+1; it != ve.end(); it++){string ss = *it;//相当于取到了vector中的字符串if (ss[0] == '-' && str.find(ss[1]) != -1)//是命令{pos = str.find(ss[1]);if (pos+1<str.length()&&str[pos + 1] == ':')//说明是带参数的{if (it + 1 != ve.end()){it += 1;string paramter = *it;ans[ss[1]] = paramter;}}else//是不带参数的{ans[ss[1]] = "!";}}else//不是命令,直接break;break;}cout << "Case " << i << ":";map<char, string>::iterator iter;for (iter = ans.begin(); iter != ans.end(); iter++){if (iter->second == "!"){cout << " -" << iter->first;}elsecout << " -"<<iter->first <<" "<< iter->second;}cout << endl;} return 0;
}

无线网络


BFS深度优先搜索用处多多
1、用在迷宫问题
2、用在遍历各层寻找最少的步数(原理是一旦找到就立即返回,返回的层数一定是最小的)

#define _CRT_SECURE_NO_WARNINGS 1
#include<cstdio>
#include<cstring>
#include<stack>
#include<algorithm>
#include<iostream>
#include<string>
#include<set>
#include<map>
#include<vector>
#include<queue>
//无线网络
//思路是广度优先搜索,因为是广度优先,
//一旦到达第二个路由器就立即返回中转路由器个数,所以可以确定返回地就是最少的中转个数
using namespace std;
int n, m, k;
long long r;//n个无线路由器,m个拜访无线路由器的位置,选择最多k个位置,两无线路由器距离r
const int maxn = 210;
struct Luyou {long long x, y;int step;
}L[maxn];//最多210个路由器
int inq[maxn] = {0};//表示有没有入过队
int sum;//总的个数
int judge(long long x1, long long y1,long long x2,long long y2)//可以到达返回1,否则返回0
{if ((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) <= r * r)return 1;elsereturn 0;
}
int BFS()
{queue<Luyou> Q;Q.push(L[0]);//将起点push进去inq[0] = 1;while (!Q.empty()){Luyou top = Q.front();Q.pop();if (top.x == L[1].x && top.y == L[1].y)return top.step - 1;else{for (int i = 0; i < sum; i++){if (inq[i]) continue;if (judge(top.x, top.y, L[i].x, L[i].y))//如果可以{inq[i] = 1;Q.push({ L[i].x,L[i].y,top.step + 1 });}elsecontinue;}}}
}
int main()
{scanf("%d %d %d %lld",&n,&m,&k,&r);//sum = n + m;for (int i = 0; i < sum; i++){scanf("%lld %lld",&L[i].x,&L[i].y);L[i].step = 0;//初始化操作}printf("%d",BFS());return 0;
}

任务调度⭐

莫得思路SOS

2014-09

相邻数对


基础题,统计即可

#define _CRT_SECURE_NO_WARNINGS 1
#include<cstdio>
#include<cstring>
#include<stack>
#include<algorithm>
#include<iostream>
#include<string>
#include<set>
using namespace std;
const int maxn = 1010;
int a[maxn];
int main() {int n, i;int num = 0;scanf("%d",&n);for (i = 0; i < n; i++){       scanf("%d", &a[i]);       }sort(a,a + n);for (i = 0; i < n-1; i++){if (a[i] == a[i + 1] - 1)num++;}printf("%d",num);return 0;
}

画图


题解:思路同样是hashtable,把对图中每一块的填色设为对左下角点的标价,用hashtable[10000],来存储二维的100*100个坐标

#define _CRT_SECURE_NO_WARNINGS 1
#include<cstdio>
#include<cstring>
#include<stack>
#include<algorithm>
#include<iostream>
#include<string>
#include<set>
using namespace std;
const int maxn = 10010;
int hashtable[maxn] = {0};
int main() {int n, i,j,k;int num = 0;int x1, y1, x2, y2;scanf("%d",&n);for (i = 0; i < n; i++){        scanf("%d %d %d %d", &x1, &y1, &x2, &y2);x2--; y2--;for(j=x1;j<=x2;j++)for (k = y1; k <= y2; k++){hashtable[j * 100 + k] = 1;}}for (i = 0; i < maxn; i++){num += hashtable[i];}   printf("%d",num);return 0;
}

字符串匹配


题解:因为要输出原来的字符串S,所以记得要保存
一些有用的库函数如下:

#include<ctype.h>
isdigit(i)//判断是否是十进制数字,如果是数字,返回非0值,否则返回0
isalpha(i)//判断是否是字母
isalnum(i)//判断是否是字母或者数字
toupper(i)//将i变成大写字母
tolower(i)//将i变成小写字母
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <cstring>
#include <map>
#include <vector>
#include<string>
using namespace std;
string str;
string S;
string temp;
string func(string S)//功能:将字符串S都变成大写
{for (int i = 0; i < S.length(); i++){S[i] = toupper(S[i]);}return S;
}
int main()
{getline(cin,S);int flag;int n;scanf("%d",&flag);scanf("%d",&n);getchar();//注意吸收换行符if (flag == 1)//表示大小写敏感{for (int i = 0; i < n; i++){         str.clear();getline(cin, str);if (str.find(S) != -1)//说明找到了子字符串cout << str<<endl;}}else//表示大小写不敏感{//将S都变成大写S = func(S);for (int i = 0; i < n; i++){         str.clear();getline(cin, str);temp = func(str);if (temp.find(S) != -1)//说明找到了子字符串cout << str << endl;}}
}

最优配餐

一眼BFS,有一个要注意的就是BFS可以同时进行搜索,并且将相同地址的订单量合并!
因为超时只有40分,一次性把所有的起点都放进BFS的起始队列中,然后如果等待送达的客户数量为0,就说明送完了,可以return.

#define _CRT_SECURE_NO_WARNINGS 1
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<stack>
#include<algorithm>
#include<iostream>
#include<string>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<limits>
using namespace std;
//最优配餐-一眼BFS
int n, m, k, d;//方格图大小,分店数量,客户数量,不能经过的点的数量
const int maxn = 1010;//存储分店的地址
struct node {int x, y;int step;node() {};node(int xx, int yy, int sstep) { x = xx, y = yy, step = sstep; }//初始化操作
}Node[maxn];
int kehu[maxn][maxn];
int kehucount=0;
long long ans=0;
int tempx, tempy,tempm;
int inq[maxn][maxn];//没有入队就是0,如果已经入队,或者不可以经过就设置为1,把每个店的地址也设置为1int X[4] = { 0,0,1,-1 };
int Y[4] = { 1,-1,0,0 };
queue<node> q;
int judge(int x, int y)
{if (x < 1 || x > n || y < 1 || y > n) return 0;if (inq[x][y] == 1) return 0;return 1;
}
void BFS()
{node top, cur;while (!q.empty()){top = q.front();q.pop();//if (kehu[top.x][top.y] > 0)//{//    ans += kehu[top.x][top.y] * top.step;//因为如果就在店里配送费为0,所以不用考虑这种情况//}for (int i = 0; i < 4; i++){cur.x = top.x + X[i];cur.y = top.y + Y[i];cur.step = top.step + 1;if (judge(cur.x, cur.y))//如果符和要求{if (kehu[cur.x][cur.y] > 0){ans += kehu[cur.x][cur.y] * cur.step;kehucount--;if (kehucount == 0)return;}inq[cur.x][cur.y] = 1;q.push(cur);}}}
}
int main()
{//首先进行初始化fill(kehu[0],kehu[0]+maxn*maxn,0);//各地订单为0fill(inq[0], inq[0] + maxn * maxn, 0);scanf("%d %d %d %d",&n,&m,&k,&d);for (int i = 0; i < m; i++){scanf("%d %d", &tempx, &tempy);q.push(node(tempx,tempy,0));inq[Node[i].x][Node[i].y] = 1;}for (int i = 0; i < k; i++){scanf("%d %d %d",&tempx,&tempy,&tempm);//if (kehu[tempx][tempy] == 0)kehucount++;//客户所在地点的数量kehu[tempx][tempy] += tempm;}for (int i = 0; i < d; i++){scanf("%d %d", &tempx, &tempy);inq[tempx][tempy] = 1;//说明不能访问}BFS();printf("%lld\n",ans);return 0;
}

拼图⭐

2014-12

门禁系统


hash表记录即可

#define _CRT_SECURE_NO_WARNINGS 1
#include<cstdio>
#include<cstring>
#include<stack>
#include<algorithm>
#include<iostream>
#include<string>
#include<set>
using namespace std;
const int maxn = 1010;
int a[1010] = {0};//记录最多1000位读者出现的次数
int main() {int n, i;int id;scanf("%d",&n);for (i = 0; i < n; i++){scanf("%d",&id);a[id]++;printf("%d ",a[id]);}  return 0;
}

Z字形扫描


主要就是分情况讨论
这题有两个要点:首先是在循环内的判断需要保证先判断是否等于n,再判断是否等于1;其次是在输出的时候一定要有逻辑,知道离开循环的时候循环变量的值都是多少,会不会输出下标范围以外的,或者下一次循环期望值以外的i或者j
要注意样例给的是n=4,代码里我一开始直接用j<4来判断了,这样肯定不对,如果只得10分可能是这个原因orz

#define _CRT_SECURE_NO_WARNINGS 1
#include<cstdio>
#include<cstring>
#include<stack>
#include<algorithm>
#include<iostream>
#include<string>
#include<set>
using namespace std;
const int maxn = 510;
int a[510][510];
int main() {int n, i,j;scanf("%d",&n);for (i = 1; i <= n; i++){for (j = 1; j <= n; j++){scanf("%d", &a[i][j]);}}i = j = 1;while (i + j <= 2 * n){if (j == n) //左下{printf("%d ", a[i][j]);  i++;          while (i < n){           printf("%d ", a[i][j]);   i++;j--;}continue;}if (i == n) //右上{        printf("%d ", a[i][j]);   j++;          while (j < n){               printf("%d ", a[i][j]);   j++;i--;}continue;}if (i == 1) //左下{            printf("%d ", a[i][j]);           j++;while (j > 1){             printf("%d ", a[i][j]);i++;j--;}continue;}if (j == 1)//右上{printf("%d ", a[i][j]);i++;while (i > 1){printf("%d ", a[i][j]);i--;j++;}continue;}          }   return 0;
}

集合竞价


显示运行错误的90分代码
同样是处理每一行的字符串,选择的数据结构是结构体,用flag来表示当前操作的有效性,如果flag=1表示买入,flag=2表示卖出,flag=3表示初始状态;

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <cstring>
#include <map>
#include <vector>
#include<string>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn = 5010;
struct Buy {int flag;double p;int s;
}bs[maxn];
priority_queue<double> q;//存储开盘价
int sum;
int realsum;
int sumb;
int sums;
char op[10];//操作
bool cmp(Buy a, Buy b)
{if (a.flag != b.flag) return a.flag < b.flag;else if (a.p != b.p) return a.p < b.p;else return 1;}
int main()
{sum = 0;realsum = 0;sumb = sums = 0;int temp;for (int i = 0; i < maxn; i++){     bs[i].flag = 3;}while (scanf("%s",op) != EOF){          if (op[0] == 'b'||op[0]=='s'){      sum++;realsum++;if (op[0] == 'b'){//printf("遇到了buy\n");bs[sum].flag = 1;sumb++;}else{//printf("遇到了sell\n");bs[sum].flag = 2;sums++;}          scanf("%lf %d",&bs[sum].p,&bs[sum].s);//printf("sum=%d,flag=%d,p=%.2f,s=%d\n", sum,bs[sum].flag, bs[sum].p, bs[sum].s);//printf("sumb=%d,sums=%d\n",sumb,sums);q.push(bs[sum].p);               }       else{           scanf("%d", &temp);if (bs[temp].flag == 1)sumb--;elsesums--;bs[temp].flag =3;          realsum--;  sum++;}}sort(bs+1, bs+1 + sum, cmp);//1-sumb是买进,sumb+1到sumb+sums是卖出/*for (int i = 1; i <= realsum; i++){printf("flag=%d,p=%.2f,s=%d\n", bs[i].flag, bs[i].p, bs[i].s);}*///printf("sumb=%d\n",sumb);long long max=0;long long tempmax;double tempp=0;double ans;long long maxb;long long maxs;while (!q.empty()){maxb = maxs = 0;if (tempp != q.top()){tempp = q.top();q.pop();int i;for (i = 1; i <= realsum; i++){if (bs[i].p >= tempp && i <= sumb){maxb += bs[i].s;}if (bs[i].p <= tempp && i > sumb){maxs += bs[i].s;}}tempmax = min(maxb, maxs);if (tempmax > max){max = tempmax;ans = tempp;              }           }else{q.pop();}}printf("%.2f %lld\n", ans, max);
}

最优灌溉


这题是最小生成树算法:
在使用最小生成树算法时要注意起点是从0还是从1开始的
1、prim算法->适用于稠密图(边多)

#define _CRT_SECURE_NO_WARNINGS 1
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<stack>
#include<algorithm>
#include<iostream>
#include<string>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<limits>
using namespace std;
//最优灌溉
const int maxv = 1010;
const int INF = 1000000000;//设置为一个很大的数
int n, m,G[maxv][maxv];
int d[maxv];
int vis[maxv] = { 0 };//标记第i个点有没有被访问
long long prim()
{fill(d,d+maxv,INF);d[1] = 0;long long ans = 0;for (int i = 1; i <= n; i++){int u = -1, MIN = INF;for (int j = 1; j <= n; j++){if (vis[j] == 0 && d[j] < MIN){u = j;MIN = d[j];}}if (u == -1) return -1;vis[u] = 1;ans += d[u];for (int v = 1; v <= n; v++){if (vis[v] == 0 && G[u][v] != INF && G[u][v] < d[v])d[v] = G[u][v];}}return ans;}
int main()
{int u, v, w;scanf("%d %d",&n,&m);fill(G[0],G[0]+maxv*maxv,INF);for (int i = 0; i < m; i++){scanf("%d %d %d",&u,&v,&w);G[u][v] = G[v][u] = w;}long long ans = prim();printf("%lld\n",ans);return 0;
}

2、k算法->适用于稀疏图(边少)

货物调度

ZKW模板代码1

#define _CRT_SECURE_NO_WARNINGS 1
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<stack>
#include<algorithm>
#include<iostream>
#include<string>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<limits>
using namespace std;
#define IOS ios::sync_with_stdio(false)
#define maxn 805
#define maxm 50005
#define INF 200000005
#define ll long longstruct ZKW
{int s, t, n;int cost;bool vis[maxn];int dist[maxn];//vis两个用处:spfa里的访问标记,増广时候的访问标记,dist是每个点的距离标号int nedge, p[maxm], c[maxm], cc[maxm], nex[maxm], head[maxn];//p[i]表示以某一点出发的编号为i的边对应点,c表示编号为i的边的流量,cc表示编号为i的边的费用void addedge(int x, int y, int z, int zz)//x->y 流量 费用{p[++nedge] = y, c[nedge] = z, cc[nedge] = zz, nex[nedge] = head[x], head[x] = nedge;p[++nedge] = x, c[nedge] = 0, cc[nedge] = -zz, nex[nedge] = head[y], head[y] = nedge;}void init(int n, int s, int t)//传入有多少个点,起点及终点{this->n = n, this->s = s, this->t = t;memset(nex, -1, sizeof nex);memset(head, -1, sizeof head);cost = 0, nedge = -1;}bool spfa(int s, int t){memset(vis, 0, sizeof vis);for (int i = 0; i <= n; i++)dist[i] = INF;dist[t] = 0;vis[t] = 1;deque<int>q;q.push_back(t);while (!q.empty()){int now = q.front();q.pop_front();for (int k = head[now]; k > -1; k = nex[k])if (c[k ^ 1] && dist[p[k]] > dist[now] - cc[k]){dist[p[k]] = dist[now] - cc[k];if (!vis[p[k]]){vis[p[k]] = 1;if (!q.empty() && dist[p[k]] < dist[q.front()])q.push_front(p[k]);else q.push_back(p[k]);}}vis[now] = 0;}return dist[s] < INF;}int dfs(int x, int low){//这里就是进行増广了if (x == t){vis[t] = 1;return low;}int used = 0, a;vis[x] = 1;//这边是不是和dinic很像啊for (int k = head[x]; k > -1; k = nex[k])if (!vis[p[k]] && c[k] && dist[x] - cc[k] == dist[p[k]]){//这个条件就表示这条边可以进行増广a = dfs(p[k], min(c[k], low - used));if (a)cost += a * cc[k], c[k] -= a, c[k ^ 1] += a, used += a;//累加答案,加流等操作都在这了if (used == low)break;}return used;}int costflow(){int flow = 0;while (spfa(s, t)){//判断起点终点是否连通,不连通说明满流,做完了退出vis[t] = 1;while (vis[t]){memset(vis, 0, sizeof vis);flow += dfs(s, INF);//一直増广直到走不到为止(这样也可以省时间哦)}}return flow;//这里返回的是最大流,费用的答案在cost里}
} G;int main()
{int n, m;cin >> n >> m;//输入城市个数和道路条数int st = 0, ed = n * 7 + 2;G.init(7 * n + 5, st, ed);for (int i = 1; i <= n; i++){for (int j = 1; j <= 7; j++){int x;cin >> x;G.addedge(st, (i - 1) * 7 + j, x, 0);}for (int j = 1; j <= 7; j++){int x;cin >> x;G.addedge((i - 1) * 7 + j, ed, x, 0);}int v, w;cin >> v >> w;for (int j = 1; j <= 6; j++)G.addedge((i - 1) * 7 + j, (i - 1) * 7 + j + 1, v, w);G.addedge((i - 1) * 7 + 7, (i - 1) * 7 + 1, v, w);}for (int i = 0; i < m; i++){int x, y, z;cin >> x >> y >> z;for (int i = 1; i <= 7; i++){G.addedge((x - 1) * 7 + i, (y - 1) * 7 + i, INF, z);G.addedge((y - 1) * 7 + i, (x - 1) * 7 + i, INF, z);}}G.costflow();cout << G.cost;return 0;
}

对于每个点和他的仓库的每一天都建一个点。

aij - bij > 0 则 原点向该点连边,流量为aij-bij,费用为0。

aij - bij < 0 则该点向汇点连边,流量为bij -aij,费用为0。

对于每一天的生产点都按照给定的图建立双向变,流量inf,费用为运输费用。

对于每一天生产点向当天的仓库连一条边,流量为v,费用为w,然后仓库向下一天的能到达的生产点连边,容量为inf,费用为运输费用。 注意因为是一个周期问题,所以周7需要向周1连边。

代码2

#include <set>
#include <map>
#include <queue>
#include <cmath>
#include <vector>
#include <cstdio>
#include <utility>
#include <cstring>
#include <iostream>
#include <algorithm>
const int maxn = 3007;
const int maxm = 300003;
const int inf = 0x3f3f3f3f;int map[maxn][maxn];
int v[maxn], w[maxn];
int a[maxn][11], b[maxn][11];int _flow_cur, _cost_cur;struct Edge
{int u, v, cap, cost, next;Edge() {}Edge(int u, int v, int cap, int cost, int next): u(u), v(v), cap(cap), cost(cost), next(next) {}
} edges[maxm];int head[maxn], e_cnt;
bool visited[maxn];
int SLK[maxn], dist[maxn], _start_, _end_;void init()
{_flow_cur = _cost_cur = 0;e_cnt = 0;memset(head, -1, sizeof(head));memset(visited, 0, sizeof(visited));
}void add(int u, int v, int cap, int cost)
{edges[e_cnt] = Edge(u, v, cap, cost, head[u]); head[u] = e_cnt ++;edges[e_cnt] = Edge(v, u, 0 , -cost, head[v]); head[v] = e_cnt ++;
}bool modlabel()
{int delta = inf;for(int i = 0; i <= _end_; i ++) {if( !visited[i] && SLK[i] < delta ) {delta  = SLK[i];SLK[i] = inf;}}if(delta == inf) return false;for(int i = 0; i <= _end_; i ++) {if( visited[i] ) dist[i] += delta;}return true;
}int aug(int u, int flow, int pre)
{if( u == _end_ ) {_cost_cur += flow * dist[_start_];return flow;}visited[u] = true;int flow_rest = flow;for(int i = head[u]; ~i; i = edges[i].next) {register int v = edges[i].v;if( !visited[v] && edges[i].cap ) {int temp = dist[v] + edges[i].cost - dist[u];if( !temp ) {int delta = aug( v, std::min(flow_rest, edges[i].cap), u );if( delta > 0 ) {flow_rest        -= delta;edges[i].cap   -= delta;edges[i^1].cap += delta;}if( flow_rest == 0 ) return flow;} else {if( temp < SLK[v] ) {SLK[v] = temp;}}}}return flow - flow_rest;
}void cost_flow()
{for(int i = 0; i <= _end_; i ++) {dist[i]   = 0;SLK[i] = inf;}do {int ret = 0;do {_flow_cur += ret;memset(visited, 0, sizeof(visited));ret = aug(_start_, inf, -1);} while( ret );} while( modlabel() );
}int main()
{int n, m;while(~scanf("%d %d", &n, &m)){init();for(int i = 1; i <= n; i ++) {for(int j = 0; j <= 6; j ++) {scanf("%d", &a[i][j]);}for(int j = 0; j <= 6; j ++) {scanf("%d", &b[i][j]);}scanf("%d %d", &v[i], &w[i]);}memset(map, 0, sizeof(map));for(int i = 0 ; i < m; i ++) {int u, v, w;scanf("%d %d %d", &u, &v, &w);map[u][v] = map[v][u] = w;}int _st = 0, _ed = 14*n+1;_start_ = _st, _end_ = _ed;for(int i = 0; i <= 6; i ++) {for(int j = 1; j <= n; j ++) {int id_b = i * n; // 生产点baseint id_c = (i + 7) * n; // 仓库点baseif(a[j][i] > b[j][i]) add(_st, id_b+j, a[j][i]-b[j][i], 0);if(a[j][i] < b[j][i]) add(id_b+j, _ed, b[j][i]-a[j][i], 0);add(id_b+j, id_c+j, v[j], w[j]);int nxt = ((i + 1) % 7) * n; // 下一天的生产点baseadd(id_c+j, nxt+j, inf, 0);for(int k = 1; k <= n; k ++) {if(!map[j][k]) continue;add(id_b+j, id_b+k, inf, map[j][k]);add(id_c+j, nxt+k, inf, map[j][k]);}}}cost_flow();printf("%d\n", _cost_cur);}
}

2015-03

图像旋转


小模拟

#define _CRT_SECURE_NO_WARNINGS 1
#include<cstdio>
#include<cstring>
#include<stack>
#include<algorithm>
#include<iostream>
#include<string>
#include<set>
using namespace std;
int a[1000][1000];
int main() {int m, n;scanf("%d %d",&n,&m);int i, j;for (i = 0; i < n; i++){for (j = 0; j < m; j++){scanf("%d",&a[i][j]);}}for (j = m-1; j >=0; j--){for (i = 0; i <n; i++){printf("%d ",a[i][j]);}printf("\n");}return 0;
}

数字排序

结构体排序

#define _CRT_SECURE_NO_WARNINGS 1
#include<cstdio>
#include<cstring>
#include<stack>
#include<algorithm>
#include<iostream>
#include<string>
#include<set>
using namespace std;
const int maxn = 1010;
struct Num
{int num;int count;
}a[maxn];
bool cmp(Num a, Num b)
{if (a.count != b.count) return a.count > b.count;else return a.num < b.num;
}
int main() {int n;int i;int num;scanf("%d",&n);for (i = 0; i < maxn; i++){a[i].num = i;a[i].count = 0;}for (i = 0; i < n; i++){scanf("%d",&num);a[num].count++;}sort(a, a + maxn,cmp);i = 0;while (a[i].count != 0){printf("%d %d\n", a[i].num, a[i].count);i++;}    return 0;
}

节日


典型的年份和日期问题:有几个地方是通用模板
1、求闰年

int run(int year)//闰年返回1,非闰年返回0
{if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)return 1;//是闰年elsereturn 0;//不是闰年
}

2、计算是星期几
这里是已知1850年1月1日是星期2

int compute(int y, int a)
{int sum = 0;for (int i = 1850; i <= y - 1; i++){sum += dayday[run(i)];}//int flag = run(y);for (int i = 1; i <= a - 1; i++){sum += mouth[flag][i];}sum++;//因为是星期2,所以sum++sum %= 7;sum++;return sum;
}

代码:

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<cstdio>
#include<string>
#include<vector>
#include<queue>
#include<stack>
#include<algorithm>
using namespace std;
int year1, year2;
int a, b, c;
int mouth[2][13] = { {0,31,28,31,30,31,30,31,31,30,31,30,31}, {0,31,29,31,30,31,30,31,31,30,31,30,31} };
//此函数计算y年a月是星期几
int dayday[2] = { 365,366 };
int run(int year)//闰年返回1,非闰年返回0
{if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)return 1;//是闰年elsereturn 0;//不是闰年
}
int compute(int y, int a)
{int sum = 0;for (int i = 1850; i <= y - 1; i++){sum += dayday[run(i)];}//int flag = run(y);for (int i = 1; i <= a - 1; i++){sum += mouth[flag][i];}sum++;sum %= 7;sum++;return sum;
}int main() {scanf("%d %d %d %d %d",&a,&b,&c,&year1,&year2);for (int y = year1; y <= year2; y++){int tempb = b;//计算y年a月1号是星期几int days = compute(y,a);//printf("是星期%d\n",days);int day = 1;//天数        int sumday = mouth[run(y)][a];//最多能数到几号//printf("sumday=%d\n",sumday);while (day<=sumday){if (days == c)tempb--;if (tempb == 0)break;days++;if(days>7)days = days % 7;day++;}if (day > sumday)printf("none\n");elseprintf("%d/%02d/%02d\n",y,a,day);//注意加上02,不然只有30分}return 0;
}

网络延时


方法1
求全源最短路径里面长度最大的:
题目的输入保证了所有的点都是可以相互连接的
这样maxv不可以取得太大,否则会运行错误

#define _CRT_SECURE_NO_WARNINGS 1
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<stack>
#include<algorithm>
#include<iostream>
#include<string>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<limits>
using namespace std;
const int INF = 1000000000;
const int maxv = 210;//最大顶点数
int n, m;
int dis[maxv][maxv];
void Floyd()
{for (int k = 1; k <= n; k++){for (int i = 1; i <= n; i++){for (int j = 1; j <= n; j++){if (dis[i][k] != INF && dis[k][j] != INF && dis[i][k] + dis[k][j] < dis[i][j]){dis[i][j] = dis[i][k] + dis[k][j];}}}}
}
int main()
{int u, v, w;fill(dis[0], dis[0] + maxv * maxv, INF);int d1, d2;scanf("%d %d",&d1,&d2);n = d1 + d2;//顶点数m = n - 1;//边数int temp;for (int i = 1; i <= n; i++){dis[i][i] = 0;}for (int i = 2; i <= n; i++){scanf("%d",&temp);dis[temp][i] = 1;dis[i][temp] = 1;}Floyd();int max=0;for (int i = 1; i <= n; i++){for (int j = 1; j <= n; j++){if (dis[i][j] != INF){if (dis[i][j] > max)max = dis[i][j];}         }      }printf("%d\n",max);return 0;
}

方法2:树的直径
首先从这个点BFS或DFS到最远的一个点u, 然后从这个u点BFS或DFS到另一个点v, 那么u->v的长度就是树的直径, 也就是此题答案.

#define _CRT_SECURE_NO_WARNINGS 1
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<stack>
#include<algorithm>
#include<iostream>
#include<string>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<limits>
using namespace std;const int maxn = 20000 + 5;
vector<int> G[maxn];
bool vis[maxn] = {};
int n, m, ans = 0, depth[maxn];int main()
{cin >> n >> m;for (int i = 2, u; i <= n + m; ++i) {cin >> u;G[u].push_back(i);G[i].push_back(u);}queue<int> Q;Q.push(1);vis[1] = true;int now;while (!Q.empty()) {now = Q.front();Q.pop();for (int i = 0; i < G[now].size(); ++i) {int v = G[now][i];if (vis[v]) continue;vis[v] = true;Q.push(v);}}Q.push(now);memset(vis, false, sizeof(vis));vis[now] = true;while (!Q.empty()) {now = Q.front();Q.pop();for (int i = 0; i < G[now].size(); ++i) {int v = G[now][i];if (vis[v]) continue;vis[v] = true;depth[v] = depth[now] + 1;Q.push(v);}}cout << depth[now];
}

最小花费


这题一开始想用并查集+K算法求解,但是还要算上花费,就懵了不知道要咋算了
参考1

30分代码1:

#define _CRT_SECURE_NO_WARNINGS 1
#include <cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cstdlib>
#include<iostream>
using namespace std;
#define N 100001long long p[N], ans;
bool vis[N];
typedef pair<int, int> Pair;
vector<Pair> g[N];void dfs(int s, int t, long long price)
{long long minprice;long long cost;if (s == t){cout << ans << endl;}else{vis[s] = true;for (int i = 0; i < g[s].size(); i++){if (!vis[g[s][i].first]){minprice = min(price, p[s]);cost = g[s][i].second * minprice;ans += cost;dfs(g[s][i].first, t, minprice);ans -= cost;}}}
}int main()
{std::ios::sync_with_stdio(false);int n, m;cin >> n >> m;for (int i = 1; i <= n; i++){cin >> p[i];}while (--n){int u, v, e;cin >> u >> v >> e;g[u].push_back(Pair(v, e));g[v].push_back(Pair(u, e));}while (m--){int s, t;cin >> s >> t;memset(vis, false, sizeof(vis));ans = 0;dfs(s, t, p[s]);}return 0;
}

30分代码2:

#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;struct Node {long long from, to, cost;Node (long long f, long long t, long long c) : from(f), to(t), cost(c) {}
};const long long maxn = 100000 + 5;
long long n, m, cost[maxn];
vector<Node> G[maxn];
vector<long long> Path, path, Dis, dis; // 真假path
bool vis[maxn];void DFS(long long from, long long to)
{if (from == to) {Path = path;Dis = dis;return;}for (long long i = 0, v, d; i < G[from].size(); ++i) {v = G[from][i].to;d = G[from][i].cost;if (vis[v]) continue;vis[v] = true;path.push_back(v);dis.push_back(d);DFS(v, to);path.pop_back();dis.pop_back();}
}int main()
{ios::sync_with_stdio(false);cin >> n >> m;for (long long i = 1; i <= n; ++i)cin >> cost[i];for (long long i = 1, u, v, c; i < n; ++i) {cin >> u >> v >> c;G[u].push_back(Node(u, v, c));G[v].push_back(Node(v, u, c));}for (long long i = 0, from, to; i < m; ++i) {cin >> from >> to;memset(vis, 0, sizeof(vis));path.clear();dis.clear();path.push_back(from);vis[from] = true;DFS(from, to);long long _min = cost[from], cos = 0, ans = 0;for (long long i = 0; i < Path.size() - 1; ++i) {if (cost[Path[i]] < _min) {ans += cos*_min;cos = 0;_min = cost[Path[i]];}cos += Dis[i];}ans += _min*cos;cout << ans << endl;}
}

2015-09

数列分段

#define _CRT_SECURE_NO_WARNINGS 1
#include<cstdio>
#include<cstring>
#include<stack>
#include<algorithm>
#include<iostream>
#include<string>
#include<set>
using namespace std;
int main() {int n, num, i;int duibi;int duan;scanf("%d",&n);scanf("%d",&num);duibi = num;duan = 1;for (i = 1; i < n; i++){scanf("%d", &num);if (num != duibi){       duan++;duibi = num;}}printf("%d",duan);return 0;
}

日期计算


设置一个二位数组存放各个月份的日期

#define _CRT_SECURE_NO_WARNINGS 1
#include<cstdio>
#include<cstring>
#include<stack>
#include<algorithm>
#include<iostream>
#include<string>
#include<set>
using namespace std;
int mouths[2][13] = { {0,31,28,31,30,31,30,31,31,30,31,30,31},{0,31,29,31,30,31,30,31,31,30,31,30,31} };
int main() {int year, days;int mouth=0, day;scanf("%d %d",&year,&days);int flag;if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)flag = 1;elseflag = 0;while (days > 0){if (days <= mouths[flag][mouth + 1])break;else{days -= mouths[flag][mouth + 1];mouth++;} }printf("%d\n%d",mouth+1,days);return 0;
}

模板生成系统


比较友好的是这题给出了输入的行数,进行逐行替换即可

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<cstdio>
#include<string>
#include<vector>
#include<queue>
#include<stack>
#include<algorithm>
#include<map>
using namespace std;
vector<string> str;
string tempstr;
string str1, str2;
map<string, string> mp;
int n, m;
int main() {scanf("%d %d",&m,&n);getchar();for (int i = 0; i < m; i++){getline(cin,tempstr);str.push_back(tempstr);}for (int i = 0; i < n; i++){getline(cin,tempstr);     int t1 = tempstr.find("\"");        str1 = tempstr.substr(0,t1-1);tempstr.erase(0,t1+1);int t2 = tempstr.find("\"");str2 = tempstr.substr(0,t2);mp[str1] = str2;        }map<string, string>::iterator it;/*for ( it = mp.begin(); it!=mp.end(); it++){cout << it->first << " " << it->second << endl;}*/for (int i = 0; i < m; i++){int prev, next;prev = 0;while(1){if ((prev = str[i].find("{{ ", prev)) == (int)string::npos)break;if ((next = str[i].find(" }}", prev)) == (int)string::npos)break;string key = str[i].substr(prev + 3, next - prev - 3);str[i].replace(prev, next - prev + 3, mp.count(key) ? mp[key] : "");prev += mp.count(key) ? mp[key].length() : 0;   // 避免重复替换,因为替换的关键词里面可能有{{}      }for (int i = 0; i < m; i++){cout<<str[i]<<endl;}return 0;
}

高速公路


一开始用BFS做的,要么超时要么内存超限,60分,如果可以连通就设置Ins数组的值为1

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<cstdio>
#include<string>
#include<vector>
#include<queue>
#include<stack>
#include<algorithm>
#include<map>
using namespace std;
const int maxv = 1010;//城市数量
//求连通分量的个数,使用BFS邻接表
vector<int> Adj[maxv];
int n;//n为顶点数
int m;//m是单向高速公路的数量
int inq[maxv] = { 0 };//初始所有城市都没有被访问过
int ins[maxv][maxv];
int ans=0;//连通块数量
int BFS(int s)//判断u能否到达t,如果能到达,返回1,否则返回0
{queue<int> q;fill(inq,inq+maxv,0);q.push(s);inq[s] = 1;    while (!q.empty()){int u = q.front();q.pop();for (int i = 0; i < Adj[u].size(); i++){int v = Adj[u][i];         ins[s][v] = 1;//表示可以到达;ins[u][v] = 1;if (inq[v] == 0){q.push(v);inq[v] = 1;}}}return 0;//无法连通
}int main() {scanf("%d %d",&n,&m);//n个城市,m条道路int u, v;fill(ins[0],ins[0]+maxv*maxv,0);for (int i = 1; i <= m; i++){scanf("%d %d",&u,&v);//u->vAdj[u].push_back(v);//u->v}for (int i = 1; i <= n; i++){      BFS(i);}    for (int i = 1; i <= n; i++){for (int j = 1; j <= n; j++){if (ins[i][j] && ins[j][i] && j != i)ans++;}}printf("%d",ans/2);return 0;
}

有专门的Tarjan算法来解决强连通分量的问题:
Tarjan算法:
一道裸代码。
输入:
一个图有向图。
输出:
它每个强连通分量。

input:
6 8
1 3
1 2
2 4
3 4
3 5
4 6
4 1
5 6
output:
6
5
3 4 2 1
裸代码:

 #include<cstdio>#include<algorithm>#include<string.h>using namespace std;struct node {int v,next;}edge[1001];int DFN[1001],LOW[1001];int stack[1001],heads[1001],visit[1001],cnt,tot,index;
void add(int x,int y)
{edge[++cnt].next=heads[x];edge[cnt].v = y;heads[x]=cnt;return ;}void tarjan(int x)//代表第几个点在处理。递归的是点。{DFN[x]=LOW[x]=++tot;// 新进点的初始化。stack[++index]=x;//进站visit[x]=1;//表示在栈里for(int i=heads[x];i!=-1;i=edge[i].next){if(!DFN[edge[i].v]) {//如果没访问过tarjan(edge[i].v);//往下进行延伸,开始递归LOW[x]=min(LOW[x],LOW[edge[i].v]);//递归出来,比较谁是谁的儿子/父亲,就是树的对应关系,涉及到强连通分量子树最小根的事情。}else if(visit[edge[i].v ]){  //如果访问过,并且还在栈里。LOW[x]=min(LOW[x],DFN[edge[i].v]);//比较谁是谁的儿子/父亲。就是链接对应关系}}if(LOW[x]==DFN[x]) //发现是整个强连通分量子树里的最小根。{do{printf("%d ",stack[index]);visit[stack[index]]=0;index--;}while(x!=stack[index+1]);//出栈,并且输出。printf("\n");}return ;}int main(){memset(heads,-1,sizeof(heads));int n,m;scanf("%d%d",&n,&m);int x,y;for(int i=1;i<=m;i++){scanf("%d%d",&x,&y);add(x,y);}for(int i=1;i<=n;i++)if(!DFN[i])  tarjan(i);//当这个点没有访问过,就从此点开始。防止图没走完return 0;}

Tarjan板子2

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
#include<algorithm>
#include<map>
using namespace std;#define MAX 10005stack<int> s;
vector<int> G[MAX];
int DFN[MAX];
int LOW[MAX];
int vis[MAX];
int instack[MAX];
int res = 0;
int order = 0;void Tarjan(int u)
{DFN[u] = LOW[u] = ++order; //为结点u设定次序号和Low值s.push(u);//将结点u压入到堆栈当中instack[u] = 1;vis[u] = 1;for (int j = 0; j < G[u].size(); j++) //枚举每一条边{int v = G[u][j];if (vis[v] == 0){Tarjan(v); //继续DFSLOW[u] = min(LOW[u], LOW[v]);}else if (instack[v]) //如果结点v仍然在栈内{LOW[u] = min(LOW[u], DFN[v]);}}if (DFN[u] == LOW[u])//如果结点u是强联通分量的根{int cnt = 0;int m;do {m = s.top(); //将结点m退栈,说明此事结点m是强联通分量中的一个顶点//printf("%d ", m);//板子注释1instack[m] = 0;s.pop();cnt++;} while (m != u);// printf("\n");//板子注释2if (cnt > 1){res = res + cnt * (cnt - 1) / 2;}}return;
}int main()
{int n, m;int a, b;scanf("%d%d", &n, &m);memset(vis, 0, sizeof(vis));memset(G, 0, sizeof(G));memset(DFN, 0, sizeof(DFN));memset(LOW, 0, sizeof(LOW));memset(instack, 0, sizeof(instack));for (int i = 0; i < m; i++){scanf("%d %d", &a, &b);G[a].push_back(b);}for (int i = 1; i <= n; i++){if (vis[i] == 0){vis[i] = 1;Tarjan(i);}}printf("%d\n", res);return 0;
}

最佳文章

AC自动机+矩阵快速幂
参考链接
题意: 大概就是告诉你一个字典,字典里字母总个数不超过100,要构造一个长度为m(<=1e15)的串,要含字典中的单词最多,输出最多的数量,可以重叠

思路:看数据大小,再根据做题的经验,很容易就想到AC自动机来优化状态,再用矩阵快速幂来优化dp,但是这题很特别。
我们先把dp写出来
dp[i][j]=max(dp[i-1][j可能的上一个状态])+End[j]
i是长度,j是在AC自动机中的节点
但是,我们能发现,一般的矩阵快速幂都只能用来完成线性递推,通常是用来解决d[i][j]=Ad[i-1][a1]+Bd[i-2][a2]+…类似的问题
这题缺是来维护最大值。
这里就要讲到了矩阵乘法的变形了。之所以矩阵乘法是可行的是因为乘法的结合律,但是加法和max()同样有结合律
我们再回顾一下矩阵快速幂的另外一道经典题,告诉你一个有向图,可能有重边,告诉你起点和终点,要你恰好k步从起点走到终点,有多少种方法。
最后,我们的dp是这样写的
dp[i][j]=sigma(dp[i][k]*dp[k][j])
我们都知道,这个题的答案就只要拿邻接矩阵求幂,然后把第0列的数字加起来就行了。
我们如果把sigma改成max,把乘号改成加号,那么就和这道题的方程完全一样了。
实际上,这种做法是可行的!
对于这道题,我们只需要对矩阵乘法的定义稍作修改,就能用来优化取最大值的dp了!
这种dp是很常见的,有了这种矩阵快速幂的方法,又为我们加速dp优化打开了一个新世界的大门。

#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <Stack>
#include <queue>
#include <cstdio>
#include <cctype>
#include <bitset>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
#define fuck(x) cout << "[" << x << "]"
#define FIN freopen("input.txt", "r", stdin)
#define FOUT freopen("output.txt", "w+", stdout)
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef vector<LL> vec;
typedef vector<vec> mat;const int MX = 1e4 + 5;
const LL INF = 0x3f3f3f3f3f3f3f3f;int rear, root;
int Next[MX][26], Fail[MX], End[MX];
int New() {rear++;End[rear] = 0;for(int i = 0; i < 26; i++) {Next[rear][i] = -1;}return rear;
}
void Init() {rear = 0;root = New();
}
void Add(char *A) {int n = strlen(A), now = root;for(int i = 0; i < n; i++) {int id = A[i] - 'a';if(Next[now][id] == -1) {Next[now][id] = New();}now = Next[now][id];}End[now]++;
}
void mat_fill(mat &A, LL val) {for(int i = 0; i < A.size(); i++) {for(int j = 0; j < A[0].size(); j++) {A[i][j] = val;}}
}
mat Build() {queue<int>Q;Fail[root] = root;for(int i = 0; i < 26; i++) {if(Next[root][i] == -1) {Next[root][i] = root;} else {Fail[Next[root][i]] = root;Q.push(Next[root][i]);}}while(!Q.empty()) {int u = Q.front(); Q.pop();End[u] += End[Fail[u]];for(int i = 0; i < 26; i++) {if(Next[u][i] == -1) {Next[u][i] = Next[Fail[u]][i];} else {Fail[Next[u][i]] = Next[Fail[u]][i];Q.push(Next[u][i]);}}}mat A(rear, vec(rear));mat_fill(A, -INF);for(int i = 1; i <= rear; i++) {for(int j = 0; j < 26; j++) {int chd = Next[i][j];A[chd - 1][i - 1] = End[chd];}}return A;
}
mat mat_mul(mat &A, mat &B) {mat C(A.size(), vec(B[0].size()));mat_fill(C, -INF);for(int i = 0; i < A.size(); i++) {for(int j = 0; j < B[0].size(); j++) {for(int k = 0; k < B.size(); k++) {if(A[i][k] + B[k][j] >= 0) {C[i][j] = max(C[i][j], A[i][k] + B[k][j]);}}}}return C;
}
mat mat_pow(mat A, LL n) {mat B = A; n--;while(n) {if(n & 1) B = mat_mul(B, A);A = mat_mul(A, A);n >>= 1;}return B;
}
void print(mat &A) {for(int i = 0; i < A.size(); i++) {for(int j = 0; j < A[0].size(); j++) {fuck(A[i][j]);} printf("\n");}
}char S[MX];
int main() {int n; LL m; //FIN;scanf("%d%lld", &n, &m);Init();for(int i = 1; i <= n; i++) {scanf("%s", S);Add(S);}mat A = Build();A = mat_pow(A, m);LL ans = 0;for(int i = 0; i < rear; i++) {ans = max(ans, A[i][0]);}printf("%lld\n", ans);return 0;
}

2015-12

数位之和

#define _CRT_SECURE_NO_WARNINGS 1
#include<cstdio>
#include<cstring>
#include<stack>
#include<algorithm>
#include<iostream>
#include<string>
#include<set>
using namespace std;
int main() {int a;int sum=0;scanf("%d",&a);while (a != 0){sum += a % 10;a /= 10;}printf("%d",sum);return 0;
}

消除类游戏


hashtable存储

#define _CRT_SECURE_NO_WARNINGS 1
#include<cstdio>
#include<cstring>
#include<stack>
#include<algorithm>
#include<iostream>
#include<string>
#include<set>
using namespace std;
int a[30][30];
int hashtable[30][30];
int main() {int m, n;int i, j;scanf("%d %d",&n,&m);for (i = 0; i < n; i++){for (j = 0; j < m; j++){scanf("%d",&a[i][j]);hashtable[i][j] = 0;}}//先遍历每一行for (i = 0; i < n; i++){for (j = 0; j <= m - 3; j++){if (a[i][j] == a[i][j + 1] && a[i][j + 1] == a[i][j + 2]){hashtable[i][j] = 1;hashtable[i][j + 1] = 1;hashtable[i][j + 2] = 1;}}}for (j = 0; j < m; j++){for (i = 0; i <= n - 3; i++){if (a[i][j] == a[i+1][j] && a[i+1][j] == a[i+2][j]){hashtable[i][j] = 1;hashtable[i+1][j] = 1;hashtable[i+2][j] = 1;}}}for (i = 0; i < n; i++){for (j = 0; j < m; j++){if (hashtable[i][j] == 1)printf("0 ");elseprintf("%d ",a[i][j]);}printf("\n");}return 0;
}

画图

BFS深搜+hashtable来判断是横线还是竖线

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<cstdio>
#include<string>
#include<vector>
#include<queue>
#include<stack>
#include<algorithm>
#include<map>
using namespace std;
int n, q, m;
int op;//操作
const int maxn = 110;
char pic[maxn][maxn];//画布
int hashtable[maxn][maxn];//=0表示没有画线//==1表示画横线,=2表示画竖线=3表示画十字
int inq[maxn][maxn];
int X[4] = { 0,0,1,-1 };
int Y[4] = { 1,-1,0,0 };
struct node {int x;int y;
}Node;
int judge(int x, int y)//检测(x,y)是否合法
{if (x >= m || x < 0 || y >= n || y < 0) return 0;//越界if (hashtable[y][x] != 0 || inq[y][x] == 1) return 0;//已经被画线了或者已经入过队了return 1;
}
void BFS(int x,int y,char c)
{queue<node> Q;Node.x = x; Node.y = y;Q.push(Node);inq[y][x] = 1;//记录为入队pic[y][x] = c;while (!Q.empty()){node top = Q.front();Q.pop();for (int i = 0; i < 4; i++){int newX = top.x + X[i];int newY = top.y + Y[i];if (judge(newX, newY)){Node.x = newX;Node.y = newY;Q.push(Node);inq[newY][newX] = 1;pic[newY][newX] = c;}}}
}
int main() {scanf("%d %d %d",&m,&n,&q);//一共m列n行getchar();//初始化画布:for (int y = 0; y < n; y++){for (int x = 0; x < m; x++){pic[y][x] = '.';}}//初始化hashtablefill(hashtable[0],hashtable[0]+maxn*maxn,0);for (int i = 0; i < q; i++){scanf("%d",&op);if (op==1)//填充操作{//使用BFS进行广度优先搜索填充//每次填充字符的时候都要初始化inqfill(inq[0],inq[0]+maxn*maxn,0);int x, y;char c[3];scanf("%d %d %s", &x, &y, c);BFS(x,y,c[0]);}else//画线段操作{int x1, y1, x2, y2;scanf("%d %d %d %d",&x1,&y1,&x2,&y2);           if (x1 == x2)//表示画竖线{if (y1 > y2)swap(y1,y2);for (int y = y1; y <= y2; y++){if(hashtable[y][x1]==0)hashtable[y][x1] = 2;elsehashtable[y][x1] = 3;}}else//表示画横线{if (x1 > x2)swap(x1,x2);for (int x = x1; x <= x2; x++){if (hashtable[y1][x] == 0)hashtable[y1][x] = 1;elsehashtable[y1][x] = 3;}}}}//现在把画线段的操作放进pic中for (int y = 0; y < n; y++){for (int x = 0; x < m; x++){if (hashtable[y][x] == 1)//说明画横线pic[y][x] = '-';else if (hashtable[y][x] == 2)pic[y][x] = '|';//画竖线else if (hashtable[y][x] == 3)//画十字架pic[y][x] = '+';else;}}for (int y = n-1; y>=0;y--){for (int x = 0; x < m; x++){printf("%c", pic[y][x]);}printf("\n");}return 0;
}

送货


问题描述:参见上文,求字典顺序最小的解。

问题分析:这个问题是一笔画问题,或者说是欧拉路径问题。所有需要判定图是否是连通图,然后再判定是否存在欧拉路径。判定是否是连通图,可以使用并查集来实现。判定是否存在欧拉路径的条件是:无向图的所有结点的出入度均为偶数,或者有2个出入度为奇数的结点。满足这个条件的图,必然能够找到欧拉路径。由于是从结点1出发,如果有2个出入度为奇数的结点,1的出入度必须为奇数。

程序说明:程序中,使用邻接表表示图,而且使用的是集合set。集合类set有自然排序的特征,构建好集合后不用专门排序。这样做,在用DFS寻找欧拉路径时,找到的第1个解即为字典顺序最小解。
参考代码

/* CCF201512-4 送货 */#include <iostream>
#include <cstring>
#include <set>
#include <vector>
#include <stack>using namespace std;const int N = 10000;// 并查集类
int v[N+1];
class UF {private:int length;
public:UF(int n) {length = n;for(int i=0; i<=n; i++)v[i] = i;}// 压缩int Find(int x) {if(x == v[x])return x;elsereturn v[x] = Find(v[x]);}bool Union(int x, int y) {x = Find(x);y = Find(y);if(x == y) {return false;} else {v[x] = y;return true;}}
};set<int> g[N+1];          // 用邻接表存储图,用集合进行排序
stack<int> path;          // 用于保存欧拉路径
bool visited[N+1][N+1];
int nopathflag;int n, m;// 深度优先搜索
void dfs(int node)
{for(set<int>::iterator it=g[node].begin(); it!=g[node].end(); it++) {if(!visited[node][*it]) {visited[node][*it] = true;visited[*it][node] = true;dfs(*it);}}path.push(node);
}int main()
{int src, dest;// 输入数据cin >> n >> m;UF uf(n);for(int i=0; i<m; i++) {cin >> src >> dest;g[src].insert(dest);g[dest].insert(src);uf.Union(src, dest);}// 判断图的联通性nopathflag = false;int root = uf.Find(1);for(int i=2; i<=n; i++)if(uf.Find(i) != root) {nopathflag = true;break;}// 判定是否存在欧拉路径:根据出入度进行计算if(!nopathflag) {// 计算出入度int count = 0;for(int i=1; i<=n; i++)if(g[i].size() % 2 == 1)count++;if(!(count == 0 || (count == 2 && g[1].size() % 2 == 1)))nopathflag = true;}if(!nopathflag) {// 计算路径:从结点1开始深度优先搜索memset(visited, false, sizeof(visited));dfs(1);// 输出结果int t;while(!path.empty()) {t = path.top();path.pop();cout << t << ' ';}cout << endl;} else// 输出结果:未找到路径cout << -1 << endl;return 0;
}

矩阵

矩阵快速幂的板子题

#include<bits/stdc++.h>using namespace std;#define ll long long
const int maxn = 200, MOD = 1e9 + 7;
int n;struct mat {int m[maxn][maxn];
}a,b,unit;void init() {memset(a.m, 0, sizeof a.m);memset(b.m, 0, sizeof b.m);memset(unit.m, 0, sizeof unit.m);
}mat operator * (mat m1, mat m2) {mat r;for (int i = 0; i < n; i++) {for (int j = 0; j < n; j++) {int l = 0;for (int k = 0; k < n; k++) {l = l ^ (m1.m[i][k] & m2.m[k][j]);}r.m[i][j] = l;}}return r;
}mat quick_pow(mat aa, int x) {mat t = aa;while (x) {if (x & 1) {t = t * aa;}aa = aa * aa;x >>= 1;}return t;
}int main(){init();for (int i = 0; i < maxn; i++) {for (int j = 0; j < maxn; j++) {if (j == i) unit.m[i][j] = 1;else unit.m[i][j] = 0;}}cin >> n;for (int i = 0; i < n; i++) {for (int j = 0; j < n; j++){scanf("%1d", &a.m[i][j]);}}for (int j = 0; j < n; j++) scanf("%1d", &b.m[j][0]);int q; cin >> q;while (q--) {int k; cin >> k;if (k == 0) {for (int i = 0; i < n; i++) cout << b.m[i][0];cout <<endl;continue;}mat rr = quick_pow(a, k - 1) * b;for (int i = 0; i < n; i++) cout << rr.m[i][0];cout <<endl;}return 0;
}

ccf-csp 2013-2015题目总结相关推荐

  1. 以CCF CSP认证为抓手,积极探索软件基础能力递进式培养体系

    原文链接:以CCF CSP认证为抓手,积极探索软件基础能力递进式培养体系 发布单位:学会      发布时间:2017-01-20 16:16 作者:陆建峰    余立功 摘要:为提升计算机专业类学生 ...

  2. CCF CSP 201609-2 火车购票

    题目链接:http://118.190.20.162/view.page?gpid=T46 问题描述 请实现一个铁路购票系统的简单座位分配算法,来处理一节车厢的座位分配. 假设一节车厢有20排.每一排 ...

  3. 计算机能力挑战赛_蓝桥杯、PAT、CCF CSP、团体程序设计天梯赛、传智杯、计算机能力挑战赛、软考等大学生编程比赛/考试介绍...

    介绍7个适合普通大学生参加的编程比赛/考试(注:有的比赛如蓝桥杯有多种赛别,本文仅介绍其中的程序设计/编程比赛). 编程入门书籍推荐<算法笔记>,内容详细易懂,对新手非常友好,描述语言为C ...

  4. ccf csp寻宝!大冒险!(C语言)

    ccf csp寻宝!大冒险! 题目背景 暑假要到了.可惜由于种种原因,小 P 原本的出游计划取消.失望的小 P 只能留在西西艾弗岛上度过一个略显单调的假期--直到-- 某天,小 P 获得了一张神秘的藏 ...

  5. 【CCF CSP】【Python】【201903-1】小中大

    [CCF CSP][Python][201903-1] 小中大 题目要求 代码实现 主要方法 提交验证 题目要求 代码实现 1.初始版(又名完全原创版.欠优化版.无法体现"人生苦短,我用PY ...

  6. CCF CSP认证考试在线评测系统

    关于CCF CSP认证考试在线评测系统 CCF CSP认证考试简介 CCF是中国计算机学会的简称.CCF计算机软件能力认证(简称CCF CSP认证考试)是CCF于2014年推出,是CCF计算机职业资格 ...

  7. CCF CSP 序列查询新解

    CCF CSP 序列查询新解(C语言) 题目背景 上一题"序列查询"中说道: A=[A0,A1,A2,⋯,An] 是一个由 n+1 个 [0,N) 范围内整数组成的序列,满足 0= ...

  8. CCF CSP认证菜鸟刷题日志

    CCF CSP菜鸟刷题日志(c/c++) 本萌新写给自己看的,要是有大佬路过,请多多指教orz 立个flag:每日一更,至201903 9月15ccf csp,冲鸭! 今天(2019.8.18)起每天 ...

  9. python认证考试_Python入门习题(39)——CCF CSP认证考试真题:公共钥匙盒

    CCF CSP认证考试真题:共钥匙盒 问题描述 试题编号:201709-2 试题名称:公共钥匙盒 时间限制:1.0s 内存限制:256.0MB 问题描述 有一个学校的老师共用N个教室,按照规定,所有的 ...

  10. CCF CSP 201812-2 小明放学 解题思路及经验总结

    更新:多谢weixin_44714465同学指出我的错误[详见49-52行代码,已改正!].CCF CSP的OJ居然没有把这个错误检测出来,不过为了追求严谨,我们还是应该及时改正! 题目描述 试题编号 ...

最新文章

  1. windows mobile开发循序渐进(6)windows mobile device center 使用问题
  2. 拟态防御_纯素食汉堡的拟态
  3. 转-Android Studio *.jar 与 *.aar 的生成与*.aar导入项目方法
  4. alan turing_深入探讨Alan Turing的生活和遗产:5本及更多书籍
  5. jquery 动态添加,降低input表单的方法
  6. 第一部分 Word练习题
  7. CentOS 7下安装svn版本访问工具rabbitvcs
  8. python爬取千图网_scrapy之千图网全站爬虫
  9. 需要作废的增值税发票丢失了怎么办
  10. kicad最小布线宽度默认是多少_常见停车场管理系统项目的安装布线及注意事项...
  11. 轻快PDF阅读器阅读pdf文件步骤
  12. 20201114-三轴云台storm32 BGC HAKRC调试+
  13. 学计算机编程配置需求,编程对电脑配置要求高吗?
  14. 网站关键词排名优化中常见的问题及解决方法
  15. 使用highcharts做地图统计
  16. fedora 18 Could not load firmware xc3028-v27
  17. matlab在解析几何教学中的应用,Matlab在解析几何教学中的应用
  18. 浏览器内核以及解决兼容性的方法
  19. html5弯道赛车游戏截图
  20. AOS美国万代半导体和CQAOS重庆万国半导体两家公司有何关联?

热门文章

  1. Android设置全局字体大小,实现小中大字体功能
  2. Java 支付宝手机网站支付下单 支付回调 及订单查询实现
  3. figma:使用mac上的字体 | 转换ttc字体文件
  4. OkHttp 官方中文文档
  5. Python破解WIFI密码完整源代码,实测可成功破解
  6. 走出计算机安全防范的六个误区
  7. SSL数字证书申请要多少钱?
  8. 我所学到的EC-2(个人学习总结,不能保证正确,欢迎大佬指正)
  9. 183day(Lambda表达式了解)
  10. python元祖格式_python中元祖