相同的球放入不同的盒子,单源最短路径

28 篇文章 0 订阅
11 篇文章 0 订阅

货物摆放

在这里插入图片描述

暴力搞不定

有点搞笑,暴力搞不定,极其缓慢

#include <iostream>
#include <algorithm>
#include <set>
using namespace std;
#define int unsigned long long
const int N=105;
int a[5];
struct node{
	int x,y,z;
	node(int x,int y,int z):x(x),y(y),z(z){
	}
	bool operator<(const node& n)const{
		if(x!=n.x)return x<n.x;
		else if(y!=n.y)return y<n.y;
		return z<n.z;
	}
}; 
set<node> s;
int res=0;
void dfs(int x,int num){

	if(x==1){
		if(s.count(node(num,a[2],a[1]))==0){
			s.insert(node(num,a[2],a[1]));
			res++;
			cout<<res<<endl;
		}
		return;
	}

	for(int i=1;i<=num;i++){
		
		if(num!=0&&num%i==0){
			a[x]=i;
			dfs(x-1,num/i);
		}
	}
}
signed main() {
//将一个很大的数拆成3个数的乘积,问有多少种拆法
	dfs(3,2021041820210418);
	cout<<s.size();
	return 0;
}

相同的球放入不同的盒子,允许空盒,先补球再插板(高中数学)

整数的素因子分解唯一性(分配3个3到3个地方)

要把一个很大的整数拆成若干个数的乘积,很容易就要想到素因子分解,因为一个大于1的整数总是能分解成若干质因子幂次的乘积的形式

分解n发现有6个质因子,其中5 个幂次都为1,
这5个质因子,每个都有3种方法,没放的就是13^55个数已经放好的基础上,还有33要分配到3个地方,

//之前混乱思考,不值一看
但由于现在3个地方已经有数值了,再加入这3个数贡献的种数不确定,
不确定主要是因为分两次加入,在第一次加入的情况下做第二次加入就不会了
于是想将这些数一次分配到3个地方,首先把33当作另外5个质因子的
附加物好了,C(5,3) 好叭,还是不理解

//大佬指教后
5个幂次为1的质因数分配好后,再分配3个相同的数到3个地方,所以分配方式就是 前者分配方式*后者分配方式
后者分配方式可以拟合高中数学中,相同的球放入不同的盒子,允许空盒,先补球再插板 的问题,
将球分成3组需要有两块隔板,因为允许盒子为空,不符合隔板法的原理,就假设再加上3个小球(首先确保每个盒子分到了一个小球)
先补3个球,
这样一来球之间有5个空挡,在5个空挡中选两个插入隔板

#include <iostream>
#include <algorithm>
#include <math.h>
using namespace std;
#define int unsigned long long
#define pii pair<int,int>
pii a[20];
int cnt=0;
signed main() {
	int n=2021041820210418;
	int x=n;
	for(int i=2;i<=x;i++){
		if(x%i==0){
			a[cnt].first=i;
			int num=0;
			while(x%i==0){
				x/=i;
				num++;
			}
			a[cnt++].second=num;
		}
	}
	cout<<cnt<<endl;
	for(int i=0;i<cnt;i++){
		cout<<a[i].first<<"^"<<a[i].second<<endl;
	}
//分解n发现有6个质因子,其中5 个幂次都为1,
/*这5个质因子,每个都有3种方法,没放的就是1咯 3^5 
在5个数已经放好的基础上,还有3个3要分配到3个地方,

//之前混乱思考,不值一看
但由于现在3个地方已经有数值了,再加入这3个数贡献的种数不确定,
不确定主要是因为分两次加入,在第一次加入的情况下做第二次加入就不会了
于是想将这些数一次分配到3个地方,首先把3个3当作另外5个质因子的
附加物好了,C(5,3) 好叭,还是不理解

//大佬指教后
5个幂次为1的质因数分配好后,再分配3个相同的数到3个地方,所以分配方式就是 前者分配方式*后者分配方式
后者分配方式可以拟合高中数学中,相同的球放入不同的盒子,允许空盒,先补球再插板 的问题,先补3个球,这样一来球之间有5个空挡,在5个空挡中选两个插入隔板
*/

cout<<pow(3,5)*10;
/*	前16个质数的乘积会大于1e18 
	int p[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53}; 
	int res=1;
	for(int i=0;i<16;i++)res*=p[i];
	cout<<res;
	*/

	return 0;
}

	//枚举:对于3, 3、3、3时有1种,1、3、9有6种,1、1、27有3种,合计10种
	3
	1 1 1	1  A(3,3)/A(3,3) 
	1 2		A(3,2) 6
	3		3
	
	//1 1 2	A(3,3)/A(2,2)   6/2

边遍历因子边计入组合数

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
    ll n=2021041820210418;
    ll en1=sqrt(n);
    ll ans=0;
    for(ll a=1;a<=en1;a++){
        if(n%a==0){
            ll nn=n/a;
            ll en2=sqrt(nn);
            for(ll b=1;b<=en2;b++){
                if(nn%b==0){
                    ll c=nn/b;
                    if(c>=b&&b>=a){
                        set<int> s;
                        s.insert(a);
                        s.insert(b);
                        s.insert(c);

                        if(s.size()==1)ans++;
                        else if(s.size()==2)ans+=3;
                        else if(s.size()==3)ans+=6;
                    }
                }
            }
        }
    }
    printf("%lld",ans);
    return 0;
}

该思路和代码来自
这个思路,就应了 上面那种类型的问题,3个数分配到3个地方

判断型暴力

#include <bits/stdc++.h>
using namespace std;
long long int a[3031];
long long int n=2021041820210418;
long long int ans=0;
void fun()
{
    for(long long int i=1;i*i<=n;i++)
    {
        if(n%i==0)
        {
            a[ans++]=i;
            if(n/i!=i)
            a[ans++]=n/i;
        }
 
    }
}
//先预处理楚所有的因子,再枚举因子
int main()
{
    fun();
    long long int sum=0;
    for(long long int i=0;i<ans;i++)
    {
        for(long long int j=0;j<ans;j++)
        {
            for(long long int k=0;k<ans;k++)
            {
                if(a[i]*a[j]*a[k]==n)
                    sum++;
            }
        }
    }
    cout<<sum;
    return 0;
}

路径

在这里插入图片描述

Dijkstra写法(源点入队时不能标记vis呀)

#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int N=1e5;
const int inf=0x3f3f3f3f;
#define pii pair<int,int>
int gcd(int x,int y){
	if(y==0)return x;
	else return gcd(y,x%y);
}
struct edge{
	int to,nex,w;	
}e[N<<1];
int head[2200];
int cnt=0;
void add(int u,int v,int w){
	e[++cnt].w=w;
	e[cnt].to=v;
	e[cnt].nex=head[u];
	head[u]=cnt;
}
int dist[N];
int vis[N];
void Dijkstra(){
	for(int i=1;i<=2021;i++){
		dist[i]=inf;
		vis[i]=0;
	}
	dist[1]=0;
	//vis[1]=1;wocwocwocwocwocwocwoc我真的会谢 
	priority_queue<pii,vector<pii>,greater<pii> > Q;
	Q.push({0,1});//到源点的距离,和该节点编号 
	for(int t=1;t<=2021;t++){
	
		if(Q.empty()){
			//cout<<"impossible";
		/*	队列空则不连通
			求最小生成树,输出不连通
			求单源最短路径,不妨碍呀,联通的那些距离小的dist先求出来了*/ 
			return ;
		}
		//	cout<<"hhhhh";
		pii p=Q.top();Q.pop();
		int v=p.second;
		if(vis[v]){
			t--;
			continue;
		}
		vis[v]=1;
		for(int i=head[v];i;i=e[i].nex){
			int to=e[i].to;
			if(!vis[to]&&(dist[to]>dist[v]+e[i].w)){
				dist[to]=dist[v]+e[i].w;
				//cout<<to<<" "<<dist[to]<<endl;
				Q.push({dist[to],to});
			}
		}
	}
}
signed main() {
	for(int i=1;i<=2021;i++){
		for(int j=i+1;j<=2021;j++){
			if(j-i<=21){
					int w=(i*j)/gcd(i,j);
					add(i,j,w);
					add(j,i,w);
			}

		}
	}
	Dijkstra(); 
	cout<<dist[2021];//10266837
	return 0;
}
//1061109567,这是inf噢 

Floyd写法(注意k在最外层噢)

#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int N=2025;
const int inf=0x3f3f3f3f;

int gcd(int x,int y){
	if(y==0)return x;
	else return gcd(y,x%y);
}

int dist[N][N];

void Floyd(){
	for(int k=1;k<=2021;k++){//注意k在最外层噢,虽然还没看懂原理 
	for(int i=1;i<=2021;i++){
		for(int j=1;j<=2021;j++){
				if(dist[i][j]>dist[i][k]+dist[k][j]){
					dist[i][j]=dist[i][k]+dist[k][j];
				}
			}
		}
	}
} 
signed main() {
	for(int i=1;i<=2021;i++){
		for(int j=1;j<=2021;j++){
			if(i==j)dist[i][j]=0;
			else if(abs(j-i)<=21){
					int w=(i*j)/gcd(i,j);
					dist[i][j]=dist[j][i]=w;	
			}
			else dist[i][j]=dist[j][i]=inf;

		}
	}
	Floyd(); 
	cout<<dist[1][2021];//10266837 慢 
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值