「问题解决」java web项目打成jar包运行后工具类无法读取模板文件的解决方法

介绍语

本号主要是Java常用关键技术点,通用工具类的分享;以及springboot+springcloud+Mybatisplus+druid+mysql+redis+swagger+maven+docker等集成框架的技术分享;datax、kafka、flink等大数据处理框架的技术分享。文章会不断更新,欢迎码友关注点赞收藏转发!

望各位码友点击关注,冲1000粉。后面会录制一些视频教程,图文和视频结合,比如:图书介绍网站系统、抢购系统、大数据中台系统等。技术才是程序猿的最爱,码友们冲啊

如果码友觉得代码太长,可以从头到尾快速扫射一遍,了解大概即可。觉得有用后再转发收藏,以备不时之需。

正文:

项目目录结构如下:

 

我在开发博客系统的的时候,需要使用工具类FreemarkerUtil获取ftl模板文件生成html文件, idea本地运行正常,freemarker正常获取到模板并生成静态文件,如下图:

 

打包成jar包之后在服务器上运行,报如下问题:
java.io.FileNotFoundException: file:/home/myblog-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/moban does not exist.

 

百度后大悟,打包成jar包时,不能使用new File()方式获取jar包中的文件,需要用流的方式获取。所以修改代码后,在本地idea运行正常,服务器运行也正常了。

工具类源码:
修改前源代码:
这时候传递的ftlFile参数为:/moban/help-page.ftl

 package com.javalaoniu.blog.utils;  
   
 import com.javalaoniu.blog.exception.BlogBusinessException;  
 import freemarker.template.Configuration;  
 import freemarker.template.Template;  
 import org.slf4j.Logger;  
 import org.slf4j.LoggerFactory;  
   
 import java.io.File;  
 import java.io.FileWriter;  
 import java.net.URL;  
 import java.util.Map;  
   
 public class FreemarkerUtil {  
   
     private static final Logger LOGGER = LoggerFactory.getLogger(FreemarkerUtil.class);  
   
     /**  
      * 生成静态html文件  
      *  
      * @param ftlFile  模板文件  
      * @param map      用于模板中的数据  
      * @param htmlFile 输出的文件  
      */  
     public void genHtml(String ftlFile, String htmlFile, Map map) {  
         LOGGER.info("ftlFile:{}", ftlFile);  
         LOGGER.info("htmlFile:{}", htmlFile);  
         try {  
             URL resource = this.getClass().getResource(ftlFile);  
             File mobanFile = new File(resource.getPath());  
             LOGGER.info("模板文件:{}", mobanFile.getPath());  
   
             Configuration cfg = new Configuration(Configuration.VERSION_2_3_23);  
             cfg.setDirectoryForTemplateLoading(new File(mobanFile.getParent()));  
             cfg.setDefaultEncoding("utf-8");  
             Template template = cfg.getTemplate(mobanFile.getName());  
   
             //生成静态页面  
             File outFile = new File(htmlFile);  
             if (!outFile.exists()) {  
                 // 创建目录  
                 File dir = new File(outFile.getParent());  
                 dir.mkdirs();  
             }  
             if (outFile.exists()&&!outFile.isFile()) {  
                 throw new RuntimeException("输出文件错误,它不是文件");  
             }  
             LOGGER.info("outFile.getPath:{}", outFile.getPath());  
             //String ftlPath = this.getClass().getClassLoader().getResource(ftlFile)  
   
             FileWriter fw = new FileWriter(outFile);  
             template.process(map, fw);  
             LOGGER.info("输出文件:{}", outFile.getPath());  
         } catch (Exception e) {  
             LOGGER.error("生成静态文件异常:", e);  
             throw new BlogBusinessException("生成静态文件异常", e);  
         }  
     }  
   
 }

修改后源代码:
这时候传递的ftlFile参数为:help-page.ftl

 package com.javalaoniu.blog.utils;  
   
 import com.javalaoniu.blog.exception.BlogBusinessException;  
 import freemarker.cache.ClassTemplateLoader;  
 import freemarker.template.Configuration;  
 import freemarker.template.Template;  
 import org.slf4j.Logger;  
 import org.slf4j.LoggerFactory;  
   
 import java.io.File;  
 import java.io.FileWriter;  
 import java.util.Map;  
   
 public class FreemarkerUtil {  
   
     private static final Logger LOGGER = LoggerFactory.getLogger(FreemarkerUtil.class);  
   
     /**  
      * 生成静态html文件  
      *  
      * @param ftlFile  模板文件  
      * @param map      用于模板中的数据  
      * @param htmlFile 输出的文件  
      */  
     public void genHtml(String ftlFile, String htmlFile, Map map) {  
         LOGGER.info("ftlFile:{}", ftlFile);  
         LOGGER.info("htmlFile:{}", htmlFile);  
         try {  
             LOGGER.info("模板文件:{}", ftlFile);  
   
             Configuration cfg = new Configuration(Configuration.VERSION_2_3_23);  
             //cfg.setDirectoryForTemplateLoading(new File(mobanFile.getParent()));// 打成jar后运行获取到的路径不对  
             //cfg.setClassForTemplateLoading(FreemarkerUtil.class, "moban");// 打成jar后运行获取到的路径不对  
             cfg.setTemplateLoader(new ClassTemplateLoader(  
                 this.getClass().getClassLoader(),  "/moban"));  
             cfg.setDefaultEncoding("utf-8");  
             Template template = cfg.getTemplate(ftlFile);  
   
             //生成静态页面  
             File outFile = new File(htmlFile);  
             if (!outFile.exists()) {  
                 // 创建目录  
                 File dir = new File(outFile.getParent());  
                 dir.mkdirs();  
             }  
             if (outFile.exists()&&!outFile.isFile()) {  
                 throw new RuntimeException("输出文件错误,它不是文件");  
             }  
             LOGGER.info("outFile.getPath:{}", outFile.getPath());  
             //String ftlPath = this.getClass().getClassLoader().getResource(ftlFile)  
   
             FileWriter fw = new FileWriter(outFile);  
             template.process(map, fw);  
             LOGGER.info("输出文件:{}", outFile.getPath());  
         } catch (Exception e) {  
             LOGGER.error("生成静态文件异常:", e);  
             throw new BlogBusinessException("生成静态文件异常", e);  
         }  
     }  
   
 }
 ​

鄙人编码十年多,在项目中也积累了一些工具类,很多工具类在每个项目都有在用,很实用。大部分是鄙人封装的,有些工具类是同事封装的,有些工具类已经不记得是ctrl+c的还是自己封装的了,现在有空就会总结项目中大部分的工具类,分享给各位码友。如果文章中涉及的代码有侵权行为请通知鄙人处理。

计划是先把工具类整理出来,正所谓工欲善其事,必先利其器。项目中不管是普通单体项目还是多模块maven项目或是分布式微服务,一部分功能模块都是可以重用的,工具类模块就是其中之一。

本文转载于网络 如有侵权请联系删除

相关文章

  • Gin 框架:添加 API 日志中间件

    介绍通过一个完整例子,在基于Gin框架的微服务中添加API日志中间件。什么是日志拦截器/中间件?日志拦截器会对每一个API请求记录日志。我们将会使用rk-boot来启动Gin框架的微服务。请访问如下地址获取完整教程:https://rkdocs.netlify.app/cn安装gogetgithub.com/rookie-ninja/rk-boot gogetgithub.com/rookie-ninja/rk-gin复制快速开始rk-boot默认集成如下两个开源库。uber-go/zap作为底层的日志库。logrus作为日志滚动。1.创建boot.yamlboot.yaml文件描述了Gin框架启动的原信息,rk-boot通过读取boot.yaml来启动Gin。为了验证,我们同时启动了commonService。commonService里包含了一系列通用API。详情:CommonService--- gin: -name:greeter#Required,nameofginentry port:8080#Required,portofginentry enabled:true#Req

  • MATLAB粒子群优化算法实现(PSO)

    PSO(PSO——ParticleSwarmOptimization)(基于种群的随机优化技术算法) 粒子群算法模仿昆虫、兽群、鸟群和鱼群等的群集行为,这些群体按照一种合作的方式寻找食物,群体中的每个成员通过学习它自身的经验和其他成员的经验来不断改变其搜索模式。概述请见:https://www.omegaxyz.com/2017/05/04/introductionofpso/Python代码请见:https://www.omegaxyz.com/2018/01/12/python_pso/MATLAB代码: MATLAB%------初始格式化--------------------------------------------------   clearall; clc; formatlong; %------给定初始化条件----------------------------------------------   c1=2;            %学习因子1 c2=2;            %学习因子2 w=0.7298;              %惯性权重 MaxD

  • 使用@ConditionalOnProperty注解

    Springboot中的注解@ConditionalOnProperty,可以通过配置文件中的属性值来判定configuration是否被注入,@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE,ElementType.METHOD}) @Documented @Conditional(OnPropertyCondition.class) public@interfaceConditionalOnProperty{ /** *String数组该属性与下面的name属性不可同时使用, *当value所对应配置文件中的值为false时,注入不生效,不为fasle注入生效 *value有多个值时,只要有一个值对应为false,则注入不成功 */ String[]value()default{}; /** *配置文件中key的前缀,可与value或name组合使用 */ Stringprefix()default""; /** *与value作用一致 */ String[]name()defau

  • 在线matlab代码学习神器Octave Online

    Octave与MATLAB完全兼容,免安装使用方便。注册和非注册功能会有不同,如下:未注册,功能简洁:注册后,功能全面:心动不如行动,赶快试试看~附录:OctaveOnline:FreeInterfacecompatiblewithMATLAB官方网址答疑部分:留言提问请参考文档:SimpleFileI/OThe save and load commandsallowdatatobewrittentoandreadfromdiskfilesinvariousformats.Thedefaultformatoffileswrittenbythe save commandcanbecontrolledusingthefunctionssave_default_options and save_precision.Asanexamplethefollowingcodecreatesa3-by-3matrixandsavesittothefile‘myfile.mat’.A=[1:3;4:6;7:9]; savemyfile.matA复制Onceoneormorevariableshavebe

  • macOS 应用注入开发简介与实践

    封面图片(来自网络)前言 本篇算是对于之前的文章MacOSX之自己动手初步学习破解软件入门关于软件安全方面学习的一个补充,有疑问的朋友们可以在评论中多多留言提问和讨论.本文中用到的项目示例工程已上传至github,供需. 0x00什么是注入?简而言之,就是在他人的App应用中,执行我们自己的代码,从而实现我们希望的目的.0x01注入可以做什么?通常来讲,通过对目标软件实现注入,主要有几个目的:增加扩展功能(例如常见的各种应用插件)免费的使用App应用的一些限制功能(比如一些vip功能)软件破解(这个目的貌似比较多些)0x02注入的方式有哪些?整体上,可以讲注入方式分为两大类:运行时注入:在App运行期,通过获取目标句柄(或内存地址)实现注入,多用于游戏外挂或应用辅助链接库注入:通常采用动态链接库方式多应用于破解软件限制本文主要介绍的是动态链接库注入的相关实践,这不仅仅局限于macOS,同时对iOS应用也具有相同的效果,希望大家可以借鉴使用.0x03如何实现注入?(重点来啦^_^)准备工具:insert_dylib:这是一个开源的命令行动态链接库注入工具下面我们通过一个实际的例子来实践一

  • Java IO 之 SequenceInputStream 原理解析

    概述今天给大家分享一个比较有意思的IO流。SequenceInputStream,听名字顾名思义。SequenceInputStream流可以把多个InputStream合并为一个InputStream.按照指定的顺序,把几个输入流连续地合并起来,使用起来像一个流一样。并且使它们像单个输入流一样出现。每个输入流依次被读取,直到到达该流的末尾。然后“序列输入流”类关闭这个流并自动地切换到下一个输入流。合并流的作用是将多个源合并合一个源。使用场景比如现在有三个文件【1.txt】、【2.txt】、【3.txt】;现在要把这三个文件按照1、2、3的顺序合并成一个文件输出到【all.txt】文件中。如果不知道有这个流,大家可能都是自己一个一个文件的去读,自己合并到一个文件中。 有了这个流,我们操作起来,代码更加优雅。示例publicclassSequenceInputStreamDemo{ publicstaticvoidsequenceStream(){ //创建字节输入流对象s1,s2,s3 try(InputStreams1=newFileInputStream(newFile("

  • BootStrap的一个标准框架的内容解释——来源于bootstrap官网

    <!DOCTYPEhtml><!--HTML5的定义--> <htmllang="zh-cn"> <head> <metacharset="utf-8"><!--页面UTF-8编码--> <metahttp-equiv="X-UA-Compatible"content="IE=edge"><!--bootStrap不支持ie的编码模式,这句代码是为了让IE运行最新的渲染模式--> <metaname="viewport"content="width=device-width,initial-scale=1"><!--初始化移动浏览显示——平时使用的移动设备是把页面放进一个虚拟的视图:viewport中,一般情况先,这个视口比屏幕宽,这样就不用把每个网页挤到很小的设备屏幕大小中,但是用户浏览需要缩放or左右平移页面才能看清楚。viewport可以让开发者控制

  • Emlog IIS7.5伪静态规则

    主页经验教程EmlogIIS7.5伪静态EmlogIIS7.5伪静态日期:2017-9-17墨渊经验教程浏览:1046次评论:1条本文已被百度收录!EMLOGIIS伪静态我也用不到,收藏一下吧,方便以后使用<?xmlversion="1.0"encoding="UTF-8"?> <configuration> <system.webServer> <rewrite> <rules> <rulename="OrgPage"stopProcessing="true"> <matchurl="^(.*)$"/> <conditionslogicalGrouping="MatchAll"> <addinput="{HTTP_HOST}"pattern="^(.*)$"/> <addinput="{REQUEST_F

  • 尴尬!iPhone14「车祸检测」再摆乌龙,坐过山车错当车祸自动报警

    【新智元导读】iPhone14「车祸检测」又摆乌龙,游乐场坐个过山车被判定为严重车祸,还自动报警了。如果你要坐一坐游乐园的过山车,最好别带iPhone14了,否则可能惊动警察。这是最近发生在美国一名牙医SaraWhite身上的麻烦事。上个月,39岁的她拿上了刚买了两天的新iPhone14Pro,登上了一所游乐场中的过山车。在高高低低、上天入地好一番快乐之后,她拿出手机一看,发现锁屏界面上有好几个未接来电,还有语音信箱里发来的消息。这些电话和邮件来自附近警方的紧急调度员,问她:您没出啥事吧?原来,这是iPhone14的新功能「碰撞检测」判断她刚才出了车祸。她的手机也自动收到消息,显示在锁屏界面上:「此iPhone机主遭遇严重车祸,且不能操作手机」,同时拨打了911报警。据警方称,电话的那头可以听到嘈杂的背景声,伴有欢呼、音乐和尖叫。警方接警后向游乐场派出了队伍,但没有发现紧急状况。虚惊一场的SaraWhite随后回拨电话告知自己一切安好。苹果「车祸检测」乌龙频发 苹果上个月宣布在新款手机iPhone14系列、智能手表WatchSeries8、SE和Ultra上推出了应对车祸的「碰撞检测」

  • 腾讯云云端IDE恢复工作空间api接口

    1.接口描述接口请求域名:cloudstudio.tencentcloudapi.com。 恢复工作空间 默认接口请求频率限制:20次/秒。 APIExplorer提供了在线调用、签名验证、SDK代码生成和快速检索接口等能力。您可查看每次调用的请求内容和返回结果以及自动生成SDK调用示例。 2.输入参数以下请求参数列表仅列出了接口请求参数和部分公共参数,完整公共参数列表见公共请求参数。 参数名称 必选 类型 描述 Action 是 String 公共参数,本接口取值:RecoverWorkspace。 Version 是 String 公共参数,本接口取值:2021-05-24。 Region 否 String 公共参数,本接口不需要传递此参数。 CloudStudioSessionTeam 是 String 无 SpaceKey 是 String 无 3.输出参数 参数名称 类型 描述 RequestId String 唯一请求ID,每次请求都会返回。定位问题时需要提供该次请求的RequestId。 4.示例示例1Re

  • 线性规划问题

    本文主要内容介绍线性规划问题(LinearProgramming)及其对偶问题(DualProblem)。 Introduction 线性规划(LinearProgramming)就是高中数学讲的那个线性规划,不过现在是从计算机的角度来谈这个问题的。 给定一个目标函数(Objectivefunction),和若干个不等式约束(Constraints): \[\max{x_1+6x_2}\\ x_1\le200\\ x_2\le300\\ x_1+x_2\le400\\ x_1,x_2\ge0 \]求出目标函数的最大值。 常规的做法是令\(c=x_1+6x_2\),然后可得\(x_2=\frac{1}{6}(-x_1+c)\),通过作图法,找出截距\(c\)的最大值。 这里的可行域是一个封闭的区域,因此最优解必然存在,最优解不存在的2种情况是: 可行域是空的,比如\(x\le1,x\ge2\). 可行域不是封闭的,比如目标函数为\(\max{x_1+x_2}\),约束条件为$x_1,x_2\ge0$。 但应当注意的是,即使可行域不是封闭的,最优解可能依然存在,比如目标函数为\(\m

  • 关于 Memcached 的一些使用

    关于Memcached的一些用法, Memcached在Windows下的版本费了很大劲,才找到。win32,win64都有。本来想自己build的,但是Cygwin下载包也是费老劲了,下不下来。 在Linux上可以使用rpm/yum直接安装,很方面,如果喜欢自己build的话,那么官网就有源码,也很方便:http://memcached.org/ 也可以在github上找到:https://github.com/memcached/memcached 不过自己build的话Memcached需要libevent的库,libevent的下载地址:http://libevent.org/ 关于Memcached的一些日常使用的语法和方式参见: http://www.cnblogs.com/jeffwongishandsome/archive/2011/11/06/2238265.html 命令的语法格式: <command><key><flags><exptime><bytes> <value> 解释说明: <

  • 整数对

    整数对 枚举余数   码队的弟弟喜欢做数学题。这不,听说你也喜欢做数学题,码队的弟弟非常高兴,决定立刻送给你一道数学题,请你完成。 给定三个整数 n,m,p求满足$ a\timesb=k\timespa×b=k×p (( 1\lea\len,1\leb\lem,k1≤a≤n,1≤b≤m,k为任意正整数 ))$的整数对 (a,b)(a,b) 的数量。 #include<bits/stdc++.h> usingnamespacestd; typedeflonglongll; intmain() { intT; scanf("%d",&T); while(T--){ lln,m,p; scanf("%lld%lld%lld",&n,&m,&p); llt=n/p; llans=0; for(llr=0;r<=p-1;r++){ if(r==0){ ans+=t*m; }elseif(r<=n%p){ ans+=(t+1)*(m/(p/__gcd(r,p)

  • 送分题,ArrayList 的扩容机制了解吗?

    1.ArrayList了解过吗?它是啥?有啥用? 众所周知,Java集合框架拥有两大接口Collection和Map,其中,Collection麾下三生子List、Set和Queue。ArrayList就实现了List接口,其实就是一个数组列表,不过作为Java的集合框架,它只能存储对象引用类型,也就是说当我们需要装载的数据是诸如int、float等基本数据类型的时候,必须把它们转换成对应的包装类。 ArrayList的底层实现是一个Object数组: 既然它是基于数组实现的,数组在内存空间中是连续分配的,那必然查询速率非常快,不过当然也肯定逃不过增删效率低的缺陷。 另外,和ArrayList一样同样实现了List接口的、我们比较常用的还有LinkedList。LinkedList比较特殊,它不仅实现了List接口,还实现了Queue接口,所以你可以看见LinkedList经常被当作队列使用: Queue<Integer>queue=newLinkedList<>(); 复制 LinkedList人如其名,它的底层自然是基于链表的,而且还是个双向链表。链表的特

  • VLOOKUP使用

    VLOOKUP(A1,$I$2:$J$6,2,0) A1:根据xx列作为依据对象列 xx列的第一个单元格 $I$2:$J$6:I2到J6的一个范围(如果要匹配出多列值),加$是为了保证匹配内容范围的固定 0:精确匹配1模糊匹配 2:匹配范围中的第几列

  • 数据库开发及ADO.NET

      SQLServer数据库 数据库 高效的存储和处理数据的介质(介质主要是两种:磁盘和内存) 为什么用数据库 海量存储数据 查找速度快 控制并发访问 安全 数据完整性 分类 关系型数据库SQL 非关系型数据库 NoSQL:notonlySQL 常见数据库 关系型数据库 大型:Oracle、DB2 中型:SQLserver、MySQL 小型:access 非关系型数据库 memcached、mongodb、redis(可同步到磁盘) 两种数据库的区别 关系型数据库:安全(存磁盘基本不可能丢失),容易理解,比较浪费空间 非关系型数据库:效率高、不安全(断电丢失) timer:3 数据库基本操作 插入数据 //如果插入所有列则表名(列1,列2,列3)可以省略 insertinto表名(列1,列2,列3)values(值1,值2,值3) 复制 删除数据 //drop是删除整张表、delete是删除数据 deletefrom表名where... 复制 更新数据 update表名set列1=新值1,列2=新值

  • Javascript 模块模式

    模块模式(ModulePattern)提供了一种代码封装的方式,可以优雅地创建非耦合的代码块。 它是利用即时函数为对象创建私有变量和特权方法。严格来说,Javascript中没有私有成员的概念,所有的对象属性都是公有的。不过,任何在函数中定义的变量,都可以认为是私有变量,因为不能在函数的外部访问这些变量。而特权方法作为闭包有权访问在函数中定义的所有变量和函数。   模块模式是多个概念的结合,包括: 闭包 命名空间 即时函数 私有变量和特权方法     模块模式的语法大概如下:   KUI.utils.namespace("KUI.module.module1"); KUI.module.module1=(function(){ varutils=KUI.utils, //privateproperties string1="string1", array1;[]; //privatefunction functionprivateFn(){ } return{ //publicproperties

  • uvm设计分析——reg

    项目中的reg_model一般只有一份,set到reg_sequence上,所以多个sequence并行启动结束的时候,regmodel会成为一个共享资源。   uvm_reg_field中的volatile,主要来设置m_check的变量,   m_check,主要用在uvm_reg的mirrortask,以及readtask,(需要map中配置check_on_read) uvm_reg_field中的desired,mirrored,m_parent,m_access变量都是local的,继承类中完全看不到,只能   通过function来得到数据。   m_access,指定field的accesspolicy。   m_written,指定是否是只能被写入一次的。   reset可以被设置为多种类型的reset的值。 主要function configure。   uvm_reg中的主要变量有,m_locked,由顶层的reg_block调用             m_parent,指向的uvm_reg_block;             m

  • jquery中对小数进行取整

    varuu=Math.floor(5.36)向下取整结果为5 varuu=Math.floor(5.88)结果为5 Math.ceil(5.33)向上取整,结果为6 Math.round(5.55)四舍五入结果为6 math.round(5.22)结果为5复制 对多位小数进行四舍五入 num是要处理的数字v为要保留的小数位数 functiondecimal(num,v){ varvv=Math.pow(10,v); returnMath.round(num*vv)/vv; }复制

  • Anroid开发环境搭建

    1.Android开发环境使用Java语言基础,我们便需要安装java环境。 2.安装java需要安装jdk(sdk)和jre.注意jdk和jre不能安装在同一个目录下否则安装后者时会覆盖前者的部分文件 3.配置环境变量,环境变量是在系统变量中配置的,不要配置错误了。在用户环境中配置无效。 4.安装完jdk和jre并配置好环境变量后可以在cmd黑边窗口中测试,输入:javac-version或java-version可以正常输出版本号,这样表示jdk和jre安装 成功,环境变量配置成功。 5.安装完jdk后可以下载eclipse了。eclipse是一款免费的软件。这款软件直接解压缩后可以直接使用,不需要安装。 6.下载好eclipse后可以安装ADT插件(注意是ADT不是SDK),不要把路径搞混了。       7.下载androidsdk文件注意文件中的内容 8.如果缺少了system-images文件夹及其子文件夹的内容将会在创建AVD时出现can'tfount'userdata.img"的错误,注意system-images下的文件结构   &

  • 「题解」CF1468M Similar Sets

    本文将同步发布于: 洛谷博客; csdn; 博客园; 简书。 题目 题目链接:洛谷、CF1468M。 题意简述 给定\(n\)个集合\(S_{1\simn}\),问是否存在\(i,j\)满足\(i\neqj\)且\(\left\lvertS_i\capS_j\right\rvert\geq2\)。 若存在,输出\(i,j\)(任意一对都可);否则输出\(-1\)。 \(n\leq10^5\),\(\sum\limits_{i=1}^n\left\lvertS_i\right\rvert\leq2\times10^5\)。 题解 图论转化 直接思考有点难,考虑经典套路,我们把这个问题转化成二分图模型。 对于一个集合\(S_i\),我们将其构造为一个左部点\(i\)。 对于一个元素\(x\),我们将其构造为一个右部点\(x\)。 如果\(x\inS_i\),那么图上有一条边\((i,x)\)。 那么\(\left\lvertS_i\capS_j\right\rvert\geq2\),就对应有至少两个右部点连到了同样的两个点。 换句话说,符合条件的答案对应了图中的一个四元环。 并且,这张

相关推荐

推荐阅读