bool is_sprime(int x){
if(x==1)return false;//1不是素数
if(x==2||x==3||x==5){//2,3,5是素数
return true;
}
if(x%2==0||x%3==0){//2和3的倍数一定不是素数
return false;
}
for(int i=5;i<=sqrt(x);i+=6){
if(x%i==0||x%(i+2)==0){
return false;
}
}
return true;
}
传送门
bool check[10000];//标记合数
vector<int> prime;
void isprime(int n){
check[0]=true;
check[1]=true;
for(int i=2;i<=n;i++){
if(!check[i])prime.push_back(i);
for(int j=0;j<prime.size()&&i*prime[j]<=n;j++){
check[i*prime[j]]=true;
if(i%prime[j]==0)break;
}
}
}
传送门
for(int i=1;i<=n;i++){//n是物品总数
for(int j=m;j>=w[i];j--){//m是背包大小
dp[j]=max(dp[j],v[i]+dp[j-w[i]]);
}
}
传送门
for(int i=1;i<=n;i++){
for(int j=w[i];j<=m;j++){
dp[j]=max(dp[j],v[i]+dp[j-w[i]]);
}
}
传送门
struct node{//包结构体
int v,w;//价值重量
node(int vv,int ww){
v=vv;
w=ww;
}
};
vector<node> goods;
for(int i=1;i<=n;i++){//拆包
int tv,tw,s;
cin>>tv>>tw>>s;
for(int k=1;k<=s;k*=2){//二进制优化
s-=k;
goods.push_back(node(tv*k,tw*k));//装包
}
if(s>0)goods.push_back(node(tv*s,tw*s));//剩下的也要装入包中
}
//01背包
for(int i=0;i<goods.size();i++){
for(int j=m;j>=goods[i].w;j--){
dp[j]=max(dp[j],goods[i].v+dp[j-goods[i].w]);
}
}
传送门
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
e[i][j]=min(e[i][j],e[i][k]+e[k][j]);
}
}
}
传送门
无法处理带有负权边和负权回路的图
book[cnt]=true;//起始点标记为访问过
for(int i=1;i<=n-1;i++){//需要松弛n-1次
int mint=INF;
for(int j=1;j<=n;j++){//找出和起始点最近的点
if(!book[j]&&dis[j]<mint){
u=j;//记录最近点下标
mint=dis[j];//记录最近点距离
}
}
book[u]=true;//标记为访问过
for(int v=1;v<=n;v++){//查询和最近点有连接的点
if(e[u][v]<INF){//保证u可以到v
dis[v]=min(dis[v],dis[u]+e[u][v]);//松弛
}
}
}
传送门
堆优化:
/*
测试数据
输入:
6 9 1
1 2 1
1 3 12
2 3 9
2 4 3
3 5 5
4 3 4
4 5 13
4 6 15
5 6 4
输出:
0 1 8 4 13 17
*/
#include
#include
#include
#include
using namespace std;
const int INF = 2147483647;
int n,m,start,dis[10005],vis[10005];
struct node{
int v,w;
node(int vv,int ww){
v=vv;
w=ww;
}
};
vector<node> ve[10005];//邻接表存图
priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > que;//小顶堆
int main(){
//输入
cin>>n>>m>>start;
for(int i=0;i<m;i++){
int x,y,z;
cin>>x>>y>>z;
ve[x].push_back(node(y,z));//建立邻接表
}
//初始化dis
for(int i=1;i<=n;i++){
dis[i]=INF;
}
dis[start]=0;
//初始化队列
que.push(make_pair(0,start));
//dijkstra算法
while(!que.empty()){
int u = que.top().second;
que.pop();
if(vis[u])continue;//这个点松弛过
vis[u]=true;
for(int i=0;i<ve[u].size();i++){//寻找和u相邻的点
int v = ve[u][i].v;
int w = ve[u][i].w;//距离
if(dis[v]>dis[u]+w){//判断是否可以松弛
dis[v]=dis[u]+w;//松弛
que.push(make_pair(dis[v],v));//入队
}
}
}
for(int i=1;i<=n;i++){
printf("%d ",dis[i]);
}
return 0;
}
#include
#include
using namespace std;
const int INF = 2147483647;
int n,m,cnt,u[500100],v[500100],w[500100];
long long dis[10100];//dis数组需要开到long long
int main(){
//输入
cin>>n>>m>>cnt;
for(int i=1;i<=m;i++){
cin>>u[i]>>v[i]>>w[i];
}
//初始化
for(int i=1;i<=n;i++){
dis[i]=INF;
}
dis[cnt]=0;
//Bellman-Ford核心语句
for(int k=1;k<=n-1;k++){
bool check=false;//判断本轮松弛最短路有没有变化
for(int i=1;i<=m;i++){
if(dis[v[i]]>dis[u[i]]+w[i]){//不能直接使用min函数
dis[v[i]]=dis[u[i]]+w[i];
check=true;//dis数组发生更新,改变check的值
}
}
if(check==false)break;//没有变化就没必要继续松弛了,提前结束
}
for(int i=1;i<=n;i++){
printf("%d ",dis[i]);
}
return 0;
}
检测负环回路:
//Bellman-Ford核心语句
for(int k=1;k<=n-1;k++){
for(int i=1;i<=m;i++){
dis[v[i]]=min(dis[v[i]],dis[u[i]]+w[i]);
}
}
bool flag=false;
for(int i=1;i<=m;i++){//n-1次松弛之后还可以松弛
if(dis[v[i]]>dis[u[i]]+w[i])flag=true;
}
if(flag)printf("此图有负权回路\n");
队列优化:
/*
5 5 1
2 3 2
1 2 -3
1 5 5
4 5 2
3 4 3
输出:
0 -3 -1 2 4
*/
#include
#include
#include
#include
using namespace std;
const int INF = 2147483647;
int n,m,start,dis[10005],vis[10005];//vis标记是否在队列中
struct node{
int v,w;
node(int vv,int ww){
v=vv;
w=ww;
}
};
vector<node> ve[10005];
queue<int> que;
int main(){
//输入
cin>>n>>m>>start;
for(int i=0;i<m;i++){
int x,y,z;
cin>>x>>y>>z;
ve[x].push_back(node(y,z));//建立邻接表
}
//初始化dis
for(int i=1;i<=n;i++){
dis[i]=INF;
}
dis[start]=0;
//初始化队列
que.push(start);
vis[start]=true;
//Bellman算法堆优化
while(!que.empty()){
int u = que.front();
//出队
que.pop();
vis[u]=false;
for(int i=0;i<ve[u].size();i++){
int v = ve[u][i].v;
int w = ve[u][i].w;
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
//不在队列中
if(!vis[v]){
que.push(v);
}
}
}
}
for(int i=1;i<=n;i++){
printf("%d ",dis[i]);
}
return 0;
}
队列优化检测负环:如果一个顶点进入队列超过n次就肯定存在负环
传送门
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
传送门
int icm(int a,int b){
return a*b/gcd(a,b);
}
传送门
void zhiyinshu(int n){
is_prime(n);//利用欧拉筛建素数表
int i=0;
while(n!=1){//n==1找完了所有质因数
if(!n%prime[i]){
printf("%d\n",prime[i]);//找到了一个质因数
n/=prime[i];
continue;//质因数可以相同
}
i++;//遍历下一个素数
}
}
传送门
void permutaion(int k){//调用permutation(0)
if(k==n){//完成一次排列
if(check()){//判断是否满足条件
//操作
}
return;
}
for(int i=k;i<n;i++){
swap(a[i],a[k]);
permutaion(k+1);
swap(a[i],a[k]);
}
}
区间全排列
void permutation(int p,int q){//对区间[p,q]进行全排列
if(p==q){//出口
if(check()){//用来检查题目的条件
//执行操作
}
return;
}
for(int i=p;i<q;i++){
swap(a[i],a[p]);
permutation(p+1,q);
swap(a[i],a[p]);
}
}
传送门
#include
#include
#include
#include
using namespace std;
vector<int> edge[100000];//邻接链表
int degree[100000];
int n,m;
void top(){
queue<int> node;
//找到入度为零的点
for(int i=1;i<=n;i++){
if(degree[i]==0){
node.push(i);
}
}
while(!node.empty()){
int now = node.front();//输出序列
printf("%d ",now);
node.pop();
for(int i=0;i<edge[now].size();i++){//找相邻节点
int dot = edge[now][i];
degree[dot]--;
if(degree[dot]==0){//入度为零入队
node.push(dot);
}
}
}
}
int main(){
cin>>n>>m;
//建立邻接链表
for(int i=0;i<=m;i++){
int x,y;
cin>>x>>y;
if(x==0&&y==0)break;
degree[y]++;
edge[x].push_back(y);
}
top();
return 0;
}
传送门
//初始化
for(int i=1;i<=n;i++){
parent[i]=i;//所有的点祖宗是自己
rank[i]=0;
}
//找根节点(找祖宗)
int find(int x){
if(x==parent[x])return x;//自己的爸爸是自己,自己就是祖宗
return parent[x]=find(parent[x]);//路径压缩,将经过的点的祖宗全部更新
}
//按秩合并集合
void unite(int x,int y){
int x_root=find(x);
int y_root=find(y);
if(x_root==y_root)return;//在同一集合中
//认层数多的树的根节点做祖宗
if(rank[x_root]>rank[y_root]){
parent[y_root]=x_root;
}else{
parent[x_root]=y_root;
if(rank[x_root]==rank[y_root]){
rank[y_root]++;//当两棵树一样高时,认y_root树做祖宗会是整体层数加一
}
}
}
传送门
//返回第一个大于或者等于x的的数的下标
int lower_bound(int x,int n,int a[]){
int lb = -1,ub = n;
while(ub-lb>1){
int mid=(ub+lb)/2;
if(x<=a[mid]){
ub=mid;
}else{
lb=mid;
}
}
return ub;
}
//返回最后一个小于或者等于x的数的下标
int upper_bound(int x,int n,int a[]){
int lb=-1,ub=n;
while(ub-lb>1){
int mid=(ub+lb)/2;
if(x>=a[mid]){
lb=mid;
}else{
ub=mid;
}
}
return lb;
}
传送门
存在一个分界点,小于分界点的不合法,大于分界点的不如他优
//求最大值情况
int solve(){
int lb=0,ub=INF;//可根据实际情况确定答案区间
for(int i=0;i<100;i++){
int mid = (lb+ub)/2;//有的情况是(lb+ub+1)/2;
if(check(mid)){//判断答案是mid使是否满足题目要求
lb=mid;//舍弃区间[lb,mid-1]
}else{
ub=mid-1;//舍弃区间[mid,ub]
}
}
return ub;//返回最大值
}
//求最小值情况
int solve(){
int lb=0,ub=INF;//根据实际情况确定答案区间
for(int i=0;i<100;i++){
int mid = (ub+lb)/2;//有的情况是(ub+lb+1)/2;
if(check(mid)){
ub=mid;//舍弃区间[mid+1,ub]
}else{
lb=mid+1;//舍弃区间[lb,mid]
}
}
return lb;
}
传送门
滑动窗口原理,涉及到元素种类问题结合map一起会更方便
还有关于连续递增M的个元素最大区间和问题,可以先将递增区间拓展到最大,然后逐渐左指针右移缩小区间,当区间长度满足条件时就是这一段递增区间的最优解,然后进入下一个递增区间同样处理即可
int i=0,j=0,sum=a[0];//初始化指针和区间和
while(i<=j&&j<n){
if(check()){//如果这段区间满足条件
//做相应操作
sum-=a[i++];//减去左指针指向的数,并且左指针后移,减小区间长度
}else{
sum+=a[++j];//右指针后移,并且加上新数,增大区间长度
}
}
传送门
传送门
//节点用结构体保存
struct Node{
int lazy,sum;
};
Node tree[10000];
//懒标记下放
void Push_Down(int node,int len){
if(!tree[node].lazy){//存在懒标记
tree[node<<1].lazy+=tree[node].lazy;//懒标记下推
tree[node<<1|1].lazy+=tree[node].lazy;//懒标记下推
tree[node<<1].sum+=(len-(len>>1))*tree[node].lazy;//更新左儿子的值
tree[node<<1|1].sum+=(len>>1)*tree[node].lazy;//更新右儿子的值
}
}
//建树
void build_tree(int node,int L,int R){
tree[node].lazy=0;//初始化lazy
if(L==R){//找到了叶子节点
tree[node].sum=arr[L];
return;
}
int mid = (L+R)>>1;
build_tree(node<<1,L,mid);
build_tree(node<<1|1,mid+1,R);
tree[node].sum=tree[node<<1].sum+tree[node<<1|1].sum;//更新父节点
}
//更新树
void update_tree(int node,int L,int R,int x,int y,int num){//将区间[x,y]所有元素执行操作
if(x<=L&&R<=y){//在需要更新的区间内
tree[node].lazy+=num;
tree[node].sum+=(R-L+1)*num;
return;
}
int mid = (L+R)>>1;
if(x<=mid){//更新区间和左子树有交集
update_tree(node<<1,L,mid,x,y,num);
}
if(y>=mid+1){//更新区间和右子树有交集
update_tree(node<<1|1,mid+1,R,x,y,num);
}
tree[node].sum=tree[node<<1].sum+tree[node<<1|1].sum;
}
//查询树
int find_tree(int node,int L,int R,int x,int y){
if(x<=L&&R<=y){
return tree[node].sum;
}
int mid = (L+R)>>1;
long long ans=0;
if(x<=mid){//查询区间和左子树有交集
ans+=find_tree(node<<1,L,mid,x,y);
}
if(y>=mid+1){//查询区间和右子树有交集
ans+=find_tree(node<<1|1,mid+1,R,x,y);
}
return ans;
}
#include
#include
#define left node*2
#define right node*2+1//左孩子
#define ll long long//右孩子
using namespace std;
const int N = 100007;
ll a[N],p;
void prin();
int n,m;
struct node{
ll muti,add,sum;
}tree[N<<2];//节点数最多不超过N的四倍
//上推
void push_up(int node){
tree[node].sum=tree[left].sum+tree[right].sum;
tree[node].sum%=p;
}
//下推
void push_down(int node,int len){
int leftlen=len-(len>>1);//做孩子区间大小
int rightlen=len>>1;//右孩子区间的大小
//下推和(注意:先乘法在加法)
tree[left].sum=tree[left].sum*tree[node].muti+tree[node].add*leftlen;
tree[left].sum%=p;
tree[right].sum=tree[right].sum*tree[node].muti+tree[node].add*rightlen;
tree[right].sum%=p;
//下推乘标记
tree[left].muti=(tree[left].muti*tree[node].muti)%p;
tree[right].muti=(tree[right].muti*tree[node].muti)%p;
//下推加标记(标记也要先乘后加)
tree[left].add= (tree[left].add*tree[node].muti+tree[node].add)%p;
tree[right].add = (tree[right].add*tree[node].muti+tree[node].add)%p;
//清空标记
tree[node].add=0;
tree[node].muti=1;
}
//建树
void build_tree(int node,int L,int R){
//初始化
tree[node].add=0;
tree[node].muti=1;
tree[node].sum=0;
if(L==R){
tree[node].sum=a[L]%p;//填入叶子节点
return;
}
int mid = (L+R)>>1;
build_tree(left,L,mid);//递归左子树
build_tree(right,mid+1,R);//递归右子树
push_up(node);//上推给父亲节点
tree[node].sum%=p;
return;
}
//更新乘法
void muti_update(int node,int L,int R,int x,int y,ll k){
if(y<L||x>R)return;//出界
if(x<=L&&R<=y){//[L,R]区间需要更新
tree[node].sum=(tree[node].sum*k)%p;//更新和
tree[node].muti=(tree[node].muti*k)%p;//更新乘法标记
tree[node].add=(tree[node].add*k)%p;//一旦执行乘法,加法标记也需要乘一遍(先乘后加原则)
return;
}
push_down(node,R-L+1);//下放标记
int mid = (L+R)>>1;
muti_update(left,L,mid,x,y,k);//递归左树
muti_update(right,mid+1,R,x,y,k);//递归右树
push_up(node);//更新父节点值
tree[node].sum%=p;
return;
}
//更新加法
void add_update(int node,int L,int R,int x,int y,int num){
if(y<L||x>R)return;//出界
if(x<=L&&R<=y){
tree[node].sum=(tree[node].sum+(R-L+1)*num)%p;//直接加就可以了,因为如果执行过乘法,已经提前处理过
tree[node].add=(tree[node].add+num)%p;//加法标记一样
return;
}
push_down(node,R-L+1);//下放标记
int mid = (L+R)>>1;
add_update(left,L,mid,x,y,num);//递归左子树
add_update(right,mid+1,R,x,y,num);//递归右子树
push_up(node);//更新父亲节点
tree[node].sum%=p;
return;
}
//查询
ll find_tree(int node,int L,int R,int x,int y){
if(y<L||x>R)return 0;//出界
if(x<=L&&R<=y){
return tree[node].sum%p;
}
push_down(node,R-L+1);//下放
int mid = (L+R)>>1;
return (find_tree(left,L,mid,x,y)+find_tree(right,mid+1,R,x,y))%p;//返回区间和注意取模
}
int main(){
scanf("%d%d%d", &n, &m, &p);
for(int i=1; i<=n; i++){
scanf("%lld", &a[i]);
}
build_tree(1, 1, n);
while(m--){
int chk;
scanf("%d", &chk);
int x, y;
long long k;
if(chk==1){
scanf("%d%d%lld", &x, &y, &k);
muti_update(1, 1, n, x, y, k);//乘法
}
else if(chk==2){
scanf("%d%d%lld", &x, &y, &k);
add_update(1, 1, n, x, y, k);//加法
}
else{
scanf("%d%d", &x, &y);
printf("%lld\n", find_tree(1, 1, n, x, y));//查询
}
}
return 0;
}
版本二:
#include
#include
#define left node*2
#define right node*2+1
#define mid (L+R)/2
#define maxn 100007
#define ll long long
using namespace std;
ll arr[maxn];
ll p,n,m;
struct node{
ll muti,add,sum;
}tree[maxn<<2];
void push_up(int node){
tree[node].sum=tree[left].sum+tree[right].sum;
tree[node].sum%=p;
}
void push_down(int node,int len){
int leftlen = len-(len>>1);
int rightlen = len>>1;
//下推和
tree[left].sum=tree[left].sum*tree[node].muti+leftlen*tree[node].add;
tree[left].sum%=p;
tree[right].sum=tree[right].sum*tree[node].muti+rightlen*tree[node].add;
tree[right].sum%=p;
//下推乘
tree[right].muti=(tree[right].muti*tree[node].muti)%p;
tree[left].muti=(tree[left].muti*tree[node].muti)%p;
//下推加
tree[left].add=tree[left].add*tree[node].muti+tree[node].add;
tree[left].add%=p;
tree[right].add=tree[right].add*tree[node].muti+tree[node].add;
tree[right].add%=p;
//标志重置
tree[node].add=0;
tree[node].muti=1;
}
//建树
void build_tree(int node,int L,int R){
tree[node].add=0;
tree[node].muti=1;
tree[node].sum=0;
if(L==R){
tree[node].sum=arr[L]%p;
return;
}
build_tree(left,L,mid);
build_tree(right,mid+1,R);
push_up(node);
}
//乘更新树
void muti_update_tree(int node,int L,int R,int x,int y,int k){
if(x<=L&&R<=y){
tree[node].sum=(tree[node].sum*k)%p;
tree[node].muti=(tree[node].muti*k)%p;
tree[node].add=(tree[node].add*k)%p;
return;
}
push_down(node,R-L+1);
if(x<=mid){
muti_update_tree(left,L,mid,x,y,k);
}
if(y>=mid+1){
muti_update_tree(right,mid+1,R,x,y,k);
}
push_up(node);
}
//加更新
void add_update_tree(int node,int L,int R,int x,int y,int num){
if(x<=L&&R<=y){
tree[node].sum=(tree[node].sum+num*(R-L+1))%p;
tree[node].add=(tree[node].add+num)%p;
return;
}
push_down(node,R-L+1);
if(x<=mid){
add_update_tree(left,L,mid,x,y,num);
}
if(y>=mid+1){
add_update_tree(right,mid+1,R,x,y,num);
}
push_up(node);
}
//查询
long long find_tree(int node,int L,int R,int x,int y){
if(x<=L&&R<=y){
return tree[node].sum%p;
}
push_down(node,R-L+1);
long long ret=0;
if(x<=mid){
ret+=find_tree(left,L,mid,x,y);
}
if(y>=mid+1){
ret+=find_tree(right,mid+1,R,x,y);
}
return ret%p;
}
int main(){
scanf("%lld %lld %lld",&n,&m,&p);
for(int i=1;i<=n;i++){
scanf("%d",&arr[i]);
}
build_tree(1,1,n);
while(m--){
int t,x,y;
scanf("%d %d %d",&t,&x,&y);
ll k;
if(t==1){
scanf("%lld",&k);
muti_update_tree(1,1,n,x,y,k);
}else if(t==2){
scanf("%lld",&k);
add_update_tree(1,1,n,x,y,k);
}else if(t==3){
printf("%lld\n",find_tree(1,1,n,x,y)%p);
}
}
return 0;
}
传送门
1.字符串输入
2.反向装入整型数组中
3.每位相加(注意进位)
4.反向输出
方法一
#include
#include
const int maxn = 100000005;
using namespace std;
int a[maxn],b[maxn],c[maxn];
int main(){
//输入
string A,B;
cin>>A>>B;
//获取长度
int la = A.length();
int lb = B.length();
//反向装入整型数组
for(int i=0;i<la;i++){
a[la-i]=A[i]-'0';
}
for(int i=0;i<lb;i++){
b[lb-i]=B[i]-'0';
}
int lc = max(la,lb);//运算结果值长度
int k=0;//进位
//计算
for(int i=1;i<=lc;i++){
c[i]=(a[i]+b[i]+k)%10;
k = (a[i]+b[i]+k)/10;
}
//还剩进位
if(k>0){
c[++lc]=k;//多进一位
}
//反向输出
for(int i=lc;i>=1;i--){
cout<<c[i];
}
return 0;
}
方法二
string add(string a,string b){
//去前导零
a=a.substr(a.find_first_not_of('0'));
b=b.substr(b.find_first_not_of('0'));
int lenA=a.length();
int lenB=b.length();
//反转从低位往高位计算
reverse(a.begin(),a.end());
reverse(b.begin(),b.end());
int len = max(lenA,lenB)+10;//便于最高位进位
string ans(len,'0');//初始化一定长度ans字符串,便于计算
//将a存入c中
for(int i=0;i<lenA;i++){
ans[i]=a[i];
}
int tmp=0;//保存进位
//进行运算
for(int i=0;i<len;i++){
if(i<lenB){
tmp+=(ans[i]-'0')+(b[i]-'0');//此时b需要参加运算
}else{
tmp+=ans[i]-'0';//b不需要参加运算
}
ans[i]=tmp%10+'0';
tmp/=10;//进位
}
//反转回来
reverse(ans.begin(),ans.end());
//去前导零
ans=ans.substr(ans.find_first_not_of('0'));
return ans;
}
传送门
1.字符串输入
2.判断两数大小,保证大数在前,是负数首先输出符号
3.反向装入整型数组中
4.每位相减(注意借位)
5.去除前导零(最少留一个0)
6.反向输出
#include
#include
using namespace std;
const int maxn = 10000005;
int a[maxn],b[maxn],c[maxn];
int main(){
//输入
string A,B;
cin>>A>>B;
//获取长度
int la = A.length();
int lb = B.length();
//判断结果正负
if(la<lb||(la==lb&&A<B)){
cout<<'-';
swap(A,B);
swap(la,lb);
}
//反向装入整型数组
for(int i=0;i<la;i++){
a[la-i]=A[i]-'0';
}
for(int i=0;i<lb;i++){
b[lb-i]=B[i]-'0';
}
int lc = la;//最终结果值长度
//计算
for(int i=1;i<=lc;i++){
if(a[i]<b[i]){//需要借位
a[i]+=10;
a[i+1]--;
}
c[i]=a[i]-b[i];
}
//去前导零,当A==B时保留一个零
while(c[lc]==0&&lc>1)lc--;
//反向输出
for(int i=lc;i>=1;i--){
cout<<c[i];
}
return 0;
}
传送门
1.字符串输入
2.反向装入整型数组中
3.交叉相乘(双重循环)
5.去除前导零(最少留一个0)
4.反向输出
#include
#include
using namespace std;
const int maxn = 10000005;
int a[maxn],b[maxn],c[maxn];
int main(){
//输入
string A,B;
cin>>A>>B;
int la = A.length();
int lb = B.length();
//反向装入整型数组
for(int i=0;i<la;i++){
a[la-i]=A[i]-'0';
}
for(int i=0;i<lb;i++){
b[lb-i]=B[i]-'0';
}
//计算,交叉相乘
for(int i=1;i<=la;i++){
for(int j=1;j<=lb;j++){
c[i+j-1]+=a[i]*b[j];//i和j乘结果放在i+j-1个位置
c[i+j]+=c[i+j-1]/10;//进位
c[i+j-1]%=10;//保留余下的
}
}
int lc = la+lb;
//去前导零
while(c[lc]==0&&lc>1)lc--;
//反向输出
for(int i=lc;i>=1;i--){
cout<<c[i];
}
return 0;
}
先把边按照权值进行排序,用贪心的思想优先选取权值较小的边,并依次连接,若出现环则跳过此边(用并查集来判断是否存在环)继续搜,直到已经使用的边的数量比总点数少一即可。
#include
#include
#include
using namespace std;
long long n,m;
struct node{
int start,end,v;
};
node edge[2000005];
int parent[5005],rank[5005];
//并查集路径压缩
int find(int x){
if(x==parent[x])return x;
return parent[x]=find(parent[x]);
}
//秩优化
void unio(int x,int y){
int x_root=find(x);
int y_root=find(y);
if(x_root==y_root)return;
if(rank[x_root]>rank[y_root]){
parent[y_root]=x_root;
}else{
parent[x_root]=y_root;
if(rank[x_root]==rank[y_root]){
rank[y_root]++;
}
}
}
bool cmp(node a,node b){
return a.v<b.v;
}
int main(){
scanf("%lld%lld",&n,&m);
//初始化并查集
for(int i=0;i<=n;i++){
parent[i]=i;
rank[i]=0;
}
for(int i=0;i<m;i++){
scanf("%d %d %d",&edge[i].start,&edge[i].end,&edge[i].v);
}
//排序
sort(edge,edge+m,cmp);
long long ans=0,con=0;
//扫描边
for(int i=0;i<m;i++){
//把祖宗都提前求出来减少复杂度
int eu=find(edge[i].start);
int ev=find(edge[i].end);
if(eu!=ev){//不在同一个集合
ans+=edge[i].v;
unio(eu,ev);//加入集合
con++;
if(con==n-1)break;//n个顶点的最小生成树有n-1条边
}
}
if(con<n-1){
cout<<"orz"<<endl;
}else{
printf("%lld\n",ans);
}
return 0;
}
传送门